зеркало из https://github.com/dotnet/infer.git
Compiler handles initialized constrained variable arrays (#412)
* MMath.Max, Min, Median throw InvalidOperationException on empty sequences. * Increased precision of MaxGaussianOp. * InnerProductArrayOp.AAverageConditional handles innerProduct near uniform. * MaxOfOthersOp has internal flag for Monte Carlo.
This commit is contained in:
Родитель
5d8f736006
Коммит
b4169dfaaa
|
@ -1975,9 +1975,13 @@ namespace Microsoft.ML.Probabilistic.Compiler.Transforms
|
|||
{
|
||||
elementInit = ConvertInitialiser(elementInit);
|
||||
elementInit = ConvertInitialiser(elementInit, arrayType, channelVarInfo, 0, false);
|
||||
elementInit = Builder.StaticGenericMethod(
|
||||
new Func<PlaceHolder, PlaceHolder, PlaceHolder>(ArrayHelper.SetTo<PlaceHolder>),
|
||||
new Type[] { outputLhs.GetExpressionType() }, outputLhs, elementInit);
|
||||
Type outputLhsType = outputLhs.GetExpressionType();
|
||||
if (Distribution.IsSettableTo(outputLhsType, outputLhsType))
|
||||
{
|
||||
elementInit = Builder.StaticGenericMethod(
|
||||
new Func<PlaceHolder, PlaceHolder, PlaceHolder>(ArrayHelper.SetTo<PlaceHolder>),
|
||||
new Type[] { outputLhsType }, outputLhs, elementInit);
|
||||
}
|
||||
IStatement init = Builder.AssignStmt(outputLhs, elementInit);
|
||||
context.OutputAttributes.Set(init, new Initializer()
|
||||
{
|
||||
|
|
|
@ -238,6 +238,10 @@ namespace Microsoft.ML.Probabilistic.Compiler.Transforms
|
|||
// this will fill in groupOf and loopInfoOfGroup
|
||||
BuildGroups(inputStmts, -1);
|
||||
g = new DependencyGraph(context, flatStmts, ignoreMissingNodes: true, ignoreRequirements: false, deleteCancels: true);
|
||||
// If replaceTargetIndex is true then TrueSkillChainTest3 fails when OptimiseInferenceCode=False
|
||||
// A required statement is not added to the init schedule by repair because it is believed to be fresh
|
||||
// due to another statement that updates the same target. For repair to work correctly, required and fresh
|
||||
// constraints must be kept consistent.
|
||||
bool replaceTargetIndex = false;
|
||||
if (replaceTargetIndex)
|
||||
{
|
||||
|
|
|
@ -4276,7 +4276,7 @@ rr = mpf('-0.99999824265582826');
|
|||
{
|
||||
IEnumerator<double> iter = list.GetEnumerator();
|
||||
if (!iter.MoveNext())
|
||||
return Double.NaN;
|
||||
throw new InvalidOperationException("Sequence contains no elements");
|
||||
double Z = iter.Current;
|
||||
while (iter.MoveNext())
|
||||
{
|
||||
|
@ -4294,7 +4294,7 @@ rr = mpf('-0.99999824265582826');
|
|||
{
|
||||
IEnumerator<double> iter = list.GetEnumerator();
|
||||
if (!iter.MoveNext())
|
||||
return Double.NaN;
|
||||
throw new InvalidOperationException("Sequence contains no elements");
|
||||
double Z = iter.Current;
|
||||
while (iter.MoveNext())
|
||||
{
|
||||
|
@ -4387,7 +4387,7 @@ rr = mpf('-0.99999824265582826');
|
|||
public static double Median(double[] array, int start, int length)
|
||||
{
|
||||
if (length <= 0)
|
||||
return Double.NaN;
|
||||
throw new InvalidOperationException("Sequence contains no elements");
|
||||
// this can be done in O(n) time, but here we take a slower shortcut.
|
||||
// Array.Sort does not sort NaNs reliably, so we must extract them first.
|
||||
double[] a = RemoveNaNs(array, start, length);
|
||||
|
|
|
@ -209,7 +209,7 @@ namespace Microsoft.ML.Probabilistic.Factors
|
|||
double prec = prior.Precision;
|
||||
if (prec == beta && prec != 0)
|
||||
{
|
||||
return Gaussian.PointMass(prior.GetMean() + alpha / prec);
|
||||
return Gaussian.PointMass((prior.MeanTimesPrecision + alpha) / prec);
|
||||
}
|
||||
double tau = prior.MeanTimesPrecision;
|
||||
double weight = beta / (prec - beta);
|
||||
|
|
|
@ -289,7 +289,15 @@ namespace Microsoft.ML.Probabilistic.Factors
|
|||
throw new ArgumentException("Incoming message from maxOfOthers is not uniform. The child of this factor must be barren.");
|
||||
if (array.Count != result.Count)
|
||||
throw new ArgumentException($"array.Count ({array.Count}) != result.Count ({result.Count})");
|
||||
MaxOfOthers(array, result);
|
||||
bool useMonteCarlo = false;
|
||||
if (useMonteCarlo)
|
||||
{
|
||||
MaxOfOthers_MonteCarlo(array, result);
|
||||
}
|
||||
else
|
||||
{
|
||||
MaxOfOthers(array, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -338,7 +346,7 @@ namespace Microsoft.ML.Probabilistic.Factors
|
|||
result[0] = Gaussian.Uniform();
|
||||
return;
|
||||
}
|
||||
int iterCount = 1000000;
|
||||
int iterCount = 100000;
|
||||
double[] x = new double[array.Count];
|
||||
var est = new ArrayEstimator<GaussianEstimator, IList<Gaussian>, Gaussian, double>(array.Count, i => new GaussianEstimator());
|
||||
for (int iter = 0; iter < iterCount; iter++)
|
||||
|
|
|
@ -363,9 +363,6 @@ namespace Microsoft.ML.Probabilistic.Factors
|
|||
return result;
|
||||
}
|
||||
|
||||
double xMean, xVariance;
|
||||
innerProduct.GetMeanAndVariance(out xMean, out xVariance);
|
||||
|
||||
double aMean, aVariance;
|
||||
double toXVariance, toXMean;
|
||||
to_innerProduct.GetMeanAndVariance(out toXMean, out toXVariance);
|
||||
|
@ -373,8 +370,21 @@ namespace Microsoft.ML.Probabilistic.Factors
|
|||
for (int k = 0; k < B.Length; k++)
|
||||
{
|
||||
A[k].GetMeanAndVariance(out aMean, out aVariance);
|
||||
double meanCorrection = toXMean - B[k] * aMean;
|
||||
double varianceCorrection = toXVariance - B[k] * B[k] * aVariance;
|
||||
|
||||
Gaussian msg = new Gaussian(xMean - (toXMean - B[k] * aMean), xVariance + toXVariance - B[k] * B[k] * aVariance);
|
||||
Gaussian msg;
|
||||
if (innerProduct.IsPointMass)
|
||||
{
|
||||
msg = new Gaussian(innerProduct.Point - meanCorrection, varianceCorrection);
|
||||
}
|
||||
else
|
||||
{
|
||||
double denom = 1 + varianceCorrection * innerProduct.Precision;
|
||||
double meanTimesPrecision = (innerProduct.MeanTimesPrecision - meanCorrection * innerProduct.Precision) / denom;
|
||||
double precision = innerProduct.Precision / denom;
|
||||
msg = Gaussian.FromNatural(meanTimesPrecision, precision);
|
||||
}
|
||||
msg = GaussianProductOpBase.AAverageConditional(msg, B[k]);
|
||||
bool damp = false;
|
||||
if (damp)
|
||||
|
|
|
@ -587,11 +587,28 @@ namespace Microsoft.ML.Probabilistic.Factors
|
|||
{
|
||||
return max;
|
||||
}
|
||||
// vx -> 0 so vx1 -> vx
|
||||
z = max.Point * a.Precision - a.MeanTimesPrecision;
|
||||
alpha = z * w1 - w2 * alpha2;
|
||||
beta = - z * alpha2 * w2 - alpha * alpha;
|
||||
if (w1 != 0) // avoid 0 * inf
|
||||
if (w1 == 0)
|
||||
{
|
||||
beta = -w2 * alpha2 * (z + w2 * alpha2);
|
||||
if (w2 == 1 && alpha2 == -z && a.Precision != 0)
|
||||
{
|
||||
// alpha2 = sqrtAPrec/R(z2) = sqrtAPrec*z2/(r1-1) = z/(r1-1)
|
||||
// z+alpha2 = z*r1/(r1-1)
|
||||
// r1 =approx 1/z2^2 = a.Precision/z^2
|
||||
// beta = -a.Precision;
|
||||
// (a.MeanTimesPrecision + alpha)/a.Precision = max.Point
|
||||
return Gaussian.PointMass(max.Point);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// only do this when w1 != 0 to avoid 0 * inf
|
||||
beta += (z * z - a.Precision) * w1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -660,11 +677,11 @@ namespace Microsoft.ML.Probabilistic.Factors
|
|||
if (alpha2 != 0) // avoid 0*infinity
|
||||
mc2 += alpha2 * v1;
|
||||
double z2 = 0, Y = 0, dY = 0, d2YiY = 0;
|
||||
const double z2small = 0;
|
||||
const double z2small = -1;
|
||||
if (vx2 == 0)
|
||||
{
|
||||
double sqrtPrec = Math.Sqrt(a.Precision);
|
||||
z2 = (mx2 - m1) * sqrtPrec;
|
||||
z2 = (mx2 * a.Precision - a.MeanTimesPrecision) / sqrtPrec;
|
||||
// When max.IsPointMass, logw2 <= -100 implies NormalCdfLn(z2) <= -100 implies z2 < -13
|
||||
if (z2 < z2small)
|
||||
{
|
||||
|
@ -684,6 +701,10 @@ namespace Microsoft.ML.Probabilistic.Factors
|
|||
// Y = (d2Y - z2)/(1 + z2^2)
|
||||
Y = (dY - 1) / z2;
|
||||
d2YiY = d2Y / Y;
|
||||
// d3Y = 2*dY + z2*d2Y
|
||||
// d2Y = (d3Y - 2 * dY) / z2
|
||||
double d3Y = 6 * MMath.NormalCdfMomentRatio(3, z2);
|
||||
d2YiY = (d3Y - 2 * dY) / (dY - 1);
|
||||
// logw2 = MMath.NormalCdfLn(z2);
|
||||
// alpha2 = -Math.Exp(Gaussian.GetLogProb(mx2, m1, vx2 + v1) - logw2);
|
||||
// = -1/sqrt(vx2+v1)/NormalCdfRatio(z2)
|
||||
|
@ -732,7 +753,7 @@ namespace Microsoft.ML.Probabilistic.Factors
|
|||
// = v + v*z*dY/Y
|
||||
// = v * (1 + z*dY/Y)
|
||||
// = v * d2Y/Y
|
||||
if (z2 < -1e8)
|
||||
if (z2 < -1e108)
|
||||
{
|
||||
// Y =approx -1/z2
|
||||
// dY =approx 1/z2^2
|
||||
|
@ -752,7 +773,7 @@ namespace Microsoft.ML.Probabilistic.Factors
|
|||
// d2Y/Y - (dY/Y)^2 = d3Y/Y/z - 2 d2Y/Y/z^2 + 2/z^2 - (d2Y^2/Y^2/z^2 - 2 d2Y/Y/z^2 + 1/z^2)
|
||||
// = d3Y/Y/z - d2Y^2/Y^2/z^2 + 1/z^2
|
||||
// Could rewrite using the method of NormalCdfRatioSqrMinusDerivative
|
||||
vc2 = dY / a.Precision;
|
||||
vc2 = 1 / z2 / a.Precision / z2;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -83,6 +83,8 @@ namespace TestApp
|
|||
Stopwatch watch = new Stopwatch();
|
||||
watch.Start();
|
||||
|
||||
new MaxGaussianOpTests().MaxTest2();
|
||||
|
||||
bool runAllTests = false;
|
||||
if (runAllTests)
|
||||
{
|
||||
|
|
|
@ -4503,7 +4503,7 @@ namespace Microsoft.ML.Probabilistic.Tests
|
|||
evBlock.CloseBlock();
|
||||
InferenceEngine engine = new InferenceEngine();
|
||||
|
||||
for (int trial = 0; trial <= 2; trial++)
|
||||
for (int trial = 0; trial <= 3; trial++)
|
||||
{
|
||||
if (trial == 0)
|
||||
{
|
||||
|
@ -4515,11 +4515,16 @@ namespace Microsoft.ML.Probabilistic.Tests
|
|||
b.ObservedValue = new[] { 0.0, 0.0 };
|
||||
cLike.ObservedValue = Gaussian.PointMass(0);
|
||||
}
|
||||
else
|
||||
else if (trial == 2)
|
||||
{
|
||||
b.ObservedValue = new[] { 0.0, 2.0 };
|
||||
cLike.ObservedValue = Gaussian.PointMass(2.3);
|
||||
}
|
||||
else
|
||||
{
|
||||
b.ObservedValue = new[] { 0.0, 2.0 };
|
||||
cLike.ObservedValue = Gaussian.FromNatural(-7.3097118076958154E-10, 1.542967011962213E-320);
|
||||
}
|
||||
|
||||
var aActual = engine.Infer<IList<Gaussian>>(a);
|
||||
VectorGaussian vectorGaussianExpected = new VectorGaussian(item.SizeAsInt);
|
||||
|
|
|
@ -33,6 +33,44 @@ namespace Microsoft.ML.Probabilistic.Tests
|
|||
/// </summary>
|
||||
public class ModelTests
|
||||
{
|
||||
[Fact]
|
||||
public void InitializeConstrainedVariableArray()
|
||||
{
|
||||
Range item = new Range(1);
|
||||
VariableArray<double> x = Variable.Array<double>(item);
|
||||
x[item] = Variable.GaussianFromMeanAndVariance(1, 2).ForEach(item);
|
||||
x.Name = nameof(x);
|
||||
double value = 1.5;
|
||||
Variable.ConstrainEqual(x[item], value);
|
||||
var xInit = Variable.Observed(default(IDistribution<double[]>));
|
||||
x.InitialiseTo(xInit);
|
||||
Variable.ConstrainPositive(x[item]);
|
||||
|
||||
InferenceEngine engine = new InferenceEngine();
|
||||
xInit.ObservedValue = new GaussianArray(item.SizeAsInt, i => new Gaussian(0, 1));
|
||||
var xActual = engine.Infer<IList<Gaussian>>(x);
|
||||
var xExpected = new GaussianArray(Gaussian.PointMass(value), item.SizeAsInt);
|
||||
Assert.Equal(xExpected, xActual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void InitializeConstrainedVariable()
|
||||
{
|
||||
Variable<double> x = Variable.GaussianFromMeanAndVariance(1, 2);
|
||||
x.Name = nameof(x);
|
||||
double value = 1.5;
|
||||
Variable.ConstrainEqual(x, value);
|
||||
var xInit = Variable.Observed(default(IDistribution<double>));
|
||||
x.InitialiseTo(xInit);
|
||||
Variable.ConstrainPositive(x);
|
||||
|
||||
InferenceEngine engine = new InferenceEngine();
|
||||
xInit.ObservedValue = new Gaussian(0, 1);
|
||||
var xActual = engine.Infer<Gaussian>(x);
|
||||
var xExpected = Gaussian.PointMass(value);
|
||||
Assert.Equal(xExpected, xActual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MarginalDividedByPriorTest()
|
||||
{
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -46,36 +47,41 @@ namespace Microsoft.ML.Probabilistic.Tests
|
|||
[Fact]
|
||||
public void MaxTest2()
|
||||
{
|
||||
Assert.False(double.IsNaN(MaxGaussianOp.AAverageConditional(Gaussian.PointMass(0), Gaussian.FromNatural(2.9785077299969009E+293, 8.7780555996490138E-16), Gaussian.PointMass(0)).MeanTimesPrecision));
|
||||
|
||||
foreach (double max in new[] { 0.0, 2.0 })
|
||||
{
|
||||
double oldm = double.NaN;
|
||||
double oldv = double.NaN;
|
||||
for (int i = 0; i < 300; i++)
|
||||
foreach (double aPrecision in new[] { 1.0/177, 8.7780555996490138E-16 })
|
||||
{
|
||||
Gaussian a = new Gaussian(System.Math.Pow(10, i), 177);
|
||||
Gaussian to_a = MaxGaussianOp.AAverageConditional(max, a, 0);
|
||||
Gaussian to_b = MaxGaussianOp.BAverageConditional(max, 0, a);
|
||||
Assert.Equal(to_a, to_b);
|
||||
if (max == 0)
|
||||
double oldm = double.NaN;
|
||||
double oldv = double.NaN;
|
||||
for (int i = 0; i < 300; i++)
|
||||
{
|
||||
Gaussian to_a2 = IsPositiveOp.XAverageConditional(false, a);
|
||||
double error = System.Math.Max(MMath.AbsDiff(to_a.MeanTimesPrecision, to_a2.MeanTimesPrecision, double.Epsilon),
|
||||
MMath.AbsDiff(to_a.Precision, to_a2.Precision, double.Epsilon));
|
||||
//Trace.WriteLine($"{a} {to_a} {to_a2} {error}");
|
||||
Assert.True(error < 1e-12);
|
||||
Gaussian a = Gaussian.FromNatural(System.Math.Pow(10, i), aPrecision);
|
||||
Gaussian to_a = MaxGaussianOp.AAverageConditional(max, a, 0);
|
||||
Gaussian to_b = MaxGaussianOp.BAverageConditional(max, 0, a);
|
||||
Assert.Equal(to_a, to_b);
|
||||
if (max == 0)
|
||||
{
|
||||
Gaussian to_a2 = IsPositiveOp.XAverageConditional(false, a);
|
||||
double error = System.Math.Max(MMath.AbsDiff(to_a.MeanTimesPrecision, to_a2.MeanTimesPrecision, double.Epsilon),
|
||||
MMath.AbsDiff(to_a.Precision, to_a2.Precision, double.Epsilon));
|
||||
Trace.WriteLine($"{i} {a} {to_a} {to_a2} {error}");
|
||||
//Assert.True(error < 1e-15);
|
||||
}
|
||||
//else Trace.WriteLine($"{a} {to_a}");
|
||||
double m, v;
|
||||
to_a.GetMeanAndVariance(out m, out v);
|
||||
if (!double.IsNaN(oldm))
|
||||
{
|
||||
Assert.True(v <= oldv);
|
||||
double olddiff = System.Math.Abs(max - oldm);
|
||||
double diff = System.Math.Abs(max - m);
|
||||
Assert.True(diff <= olddiff);
|
||||
}
|
||||
oldm = m;
|
||||
oldv = v;
|
||||
}
|
||||
//else Trace.WriteLine($"{a} {to_a}");
|
||||
double m, v;
|
||||
to_a.GetMeanAndVariance(out m, out v);
|
||||
if (!double.IsNaN(oldm))
|
||||
{
|
||||
Assert.True(v <= oldv);
|
||||
double olddiff = System.Math.Abs(max - oldm);
|
||||
double diff = System.Math.Abs(max - m);
|
||||
Assert.True(diff <= olddiff);
|
||||
}
|
||||
oldm = m;
|
||||
oldv = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -152,7 +158,7 @@ namespace Microsoft.ML.Probabilistic.Tests
|
|||
Gaussian a = Gaussian.FromMeanAndPrecision(point, System.Math.Pow(10, i));
|
||||
Gaussian to_a = MaxGaussianOp.AAverageConditional(max, a, b);
|
||||
double diff = toPoint.MaxDiff(to_a);
|
||||
//Console.WriteLine($"{a} {to_a} {to_a.MeanTimesPrecision:g17} {to_a.Precision:g17} {diff:g17}");
|
||||
//Console.WriteLine($"{i} {a} {to_a} {to_a.MeanTimesPrecision:g17} {to_a.Precision:g17} {diff:g17}");
|
||||
if (diff < 1e-14) diff = 0;
|
||||
Assert.True(diff <= oldDiff);
|
||||
oldDiff = diff;
|
||||
|
|
Загрузка…
Ссылка в новой задаче