diff --git a/docs/samples/Microsoft.ML.Samples/Dynamic/Trainers/MulticlassClassification/PermutationFeatureImportanceLoadFromDisk.cs b/docs/samples/Microsoft.ML.Samples/Dynamic/Trainers/MulticlassClassification/PermutationFeatureImportanceLoadFromDisk.cs
new file mode 100644
index 0000000000..3a94a113c4
--- /dev/null
+++ b/docs/samples/Microsoft.ML.Samples/Dynamic/Trainers/MulticlassClassification/PermutationFeatureImportanceLoadFromDisk.cs
@@ -0,0 +1,138 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Microsoft.ML;
+using Microsoft.ML.Calibrators;
+using Microsoft.ML.Data;
+using Microsoft.ML.Trainers;
+
+namespace Samples.Dynamic.Trainers.MulticlassClassification
+{
+    public static class PermutationFeatureImportanceLoadFromDisk
+    {
+        public static void Example()
+        {
+            // Create a new context for ML.NET operations. It can be used for
+            // exception tracking and logging, as a catalog of available operations
+            // and as the source of randomness.
+            var mlContext = new MLContext(seed: 1);
+
+            // Create sample data.
+            var samples = GenerateData();
+
+            // Load the sample data as an IDataView.
+            var data = mlContext.Data.LoadFromEnumerable(samples);
+
+            // Define a training pipeline that concatenates features into a vector,
+            // normalizes them, and then trains a linear model.
+            var featureColumns =
+                new string[] { nameof(Data.Feature1), nameof(Data.Feature2) };
+
+            var pipeline = mlContext.Transforms
+                .Concatenate("Features", featureColumns)
+                .Append(mlContext.Transforms.Conversion.MapValueToKey("Label"))
+                .Append(mlContext.Transforms.NormalizeMinMax("Features"))
+                .Append(mlContext.MulticlassClassification.Trainers
+                .SdcaMaximumEntropy());
+
+            // Fit the pipeline to the data and save the model
+            var model0 = pipeline.Fit(data);
+            var modelPath = "./model0.zip";
+            mlContext.Model.Save(model0, data.Schema, modelPath);
+
+            // Load the model
+            var model = mlContext.Model.Load(modelPath, out var schema);
+
+            // Transform the dataset.
+            var transformedData = model.Transform(data);
+
+            // Extract the predictor.
+            var linearPredictor = (model as TransformerChain<ITransformer>).LastTransformer as MulticlassPredictionTransformer<MaximumEntropyModelParameters>;
+
+            // Compute the permutation metrics for the linear model using the
+            // normalized data.
+            var permutationMetrics = mlContext.MulticlassClassification
+                .PermutationFeatureImportance(linearPredictor, transformedData,
+                permutationCount: 30);
+
+            // Now let's look at which features are most important to the model
+            // overall. Get the feature indices sorted by their impact on
+            // microaccuracy.
+            var sortedIndices = permutationMetrics
+                .Select((metrics, index) => new { index, metrics.MicroAccuracy })
+                .OrderByDescending(feature => Math.Abs(feature.MicroAccuracy.Mean))
+                .Select(feature => feature.index);
+
+            Console.WriteLine("Feature\tChange in MicroAccuracy\t95% Confidence in "
+                + "the Mean Change in MicroAccuracy");
+
+            var microAccuracy = permutationMetrics.Select(x => x.MicroAccuracy)
+                .ToArray();
+
+            foreach (int i in sortedIndices)
+            {
+                Console.WriteLine("{0}\t{1:G4}\t{2:G4}",
+                    featureColumns[i],
+                    microAccuracy[i].Mean,
+                    1.96 * microAccuracy[i].StandardError);
+            }
+
+            // Expected output:
+            //Feature     Change in MicroAccuracy  95% Confidence in the Mean Change in MicroAccuracy
+            //Feature2        -0.1396                 0.0008036
+            //Feature1        -0.05421                0.0006154
+
+        }
+
+        private class Data
+        {
+            public float Label { get; set; }
+
+            public float Feature1 { get; set; }
+
+            public float Feature2 { get; set; }
+        }
+
+        /// <summary>
+        /// Generate an enumerable of Data objects, creating the label as a simple
+        /// linear combination of the features.
+        /// </summary>
+        /// <param name="nExamples">The number of examples.</param>
+        /// <param name="bias">The bias, or offset, in the calculation of the
+        /// label.</param>
+        /// <param name="weight1">The weight to multiply the first feature with to
+        /// compute the label.</param>
+        /// <param name="weight2">The weight to multiply the second feature with to
+        /// compute the label.</param>
+        /// <param name="seed">The seed for generating feature values and label
+        /// noise.</param>
+        /// <returns>An enumerable of Data objects.</returns>
+        private static IEnumerable<Data> GenerateData(int nExamples = 10000,
+            double bias = 0, double weight1 = 1, double weight2 = 2, int seed = 1)
+        {
+            var rng = new Random(seed);
+            var max = bias + 4.5 * weight1 + 4.5 * weight2 + 0.5;
+            for (int i = 0; i < nExamples; i++)
+            {
+                var data = new Data
+                {
+                    Feature1 = (float)(rng.Next(10) * (rng.NextDouble() - 0.5)),
+                    Feature2 = (float)(rng.Next(10) * (rng.NextDouble() - 0.5)),
+                };
+
+                // Create a noisy label.
+                var value = (float)
+                    (bias + weight1 * data.Feature1 + weight2 * data.Feature2 +
+                    rng.NextDouble() - 0.5);
+
+                if (value < max / 3)
+                    data.Label = 0;
+                else if (value < 2 * max / 3)
+                    data.Label = 1;
+                else
+                    data.Label = 2;
+                yield return data;
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/docs/samples/Microsoft.ML.Samples/Dynamic/Trainers/Ranking/PermutationFeatureImportanceLoadFromDisk.cs b/docs/samples/Microsoft.ML.Samples/Dynamic/Trainers/Ranking/PermutationFeatureImportanceLoadFromDisk.cs
new file mode 100644
index 0000000000..e12e17554b
--- /dev/null
+++ b/docs/samples/Microsoft.ML.Samples/Dynamic/Trainers/Ranking/PermutationFeatureImportanceLoadFromDisk.cs
@@ -0,0 +1,144 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Microsoft.ML;
+using Microsoft.ML.Data;
+using Microsoft.ML.Trainers.FastTree;
+
+namespace Samples.Dynamic.Trainers.Ranking
+{
+    public static class PermutationFeatureImportanceLoadFromDisk
+    {
+        public static void Example()
+        {
+            // Create a new context for ML.NET operations. It can be used for
+            // exception tracking and logging, as a catalog of available operations
+            // and as the source of randomness.
+            var mlContext = new MLContext(seed: 1);
+
+            // Create sample data.
+            var samples = GenerateData();
+
+            // Load the sample data as an IDataView.
+            var data = mlContext.Data.LoadFromEnumerable(samples);
+
+            // Define a training pipeline that concatenates features into a vector,
+            // normalizes them, and then trains a linear model.
+            var featureColumns = new string[] { nameof(Data.Feature1), nameof(
+                Data.Feature2) };
+            var pipeline = mlContext.Transforms.Concatenate("Features",
+                featureColumns)
+                    .Append(mlContext.Transforms.Conversion.MapValueToKey("Label"))
+                    .Append(mlContext.Transforms.Conversion.MapValueToKey(
+                        "GroupId"))
+                    .Append(mlContext.Transforms.NormalizeMinMax("Features"))
+                    .Append(mlContext.Ranking.Trainers.FastTree());
+
+            // Train the model and save to disk
+            var model0 = pipeline.Fit(data);
+            var modelPath = "./model0.zip";
+            mlContext.Model.Save(model0, data.Schema, modelPath);
+
+            // Load model
+            var model = mlContext.Model.Load(modelPath, out var schema);
+
+            // Transform Data
+            var transformedData = model.Transform(data);
+
+            //  Extract the predictor
+            var linearPredictor = (model as TransformerChain<ITransformer>).LastTransformer as RankingPredictionTransformer<FastTreeRankingModelParameters>;
+
+            // Compute the permutation metrics for the linear model using the
+            // normalized data.
+            var permutationMetrics = mlContext.Ranking.PermutationFeatureImportance(
+                linearPredictor, transformedData, permutationCount: 30);
+
+            // Now let's look at which features are most important to the model
+            // overall. Get the feature indices sorted by their impact on NDCG@1.
+            var sortedIndices = permutationMetrics.Select((metrics, index) => new {
+                index,
+                metrics.NormalizedDiscountedCumulativeGains
+            })
+                .OrderByDescending(feature => Math.Abs(
+                    feature.NormalizedDiscountedCumulativeGains[0].Mean))
+
+                .Select(feature => feature.index);
+
+            Console.WriteLine("Feature\tChange in NDCG@1\t95% Confidence in the" +
+                "Mean Change in NDCG@1");
+            var ndcg = permutationMetrics.Select(
+                x => x.NormalizedDiscountedCumulativeGains).ToArray();
+            foreach (int i in sortedIndices)
+            {
+                Console.WriteLine("{0}\t{1:G4}\t{2:G4}",
+                    featureColumns[i],
+                    ndcg[i][0].Mean,
+                    1.96 * ndcg[i][0].StandardError);
+            }
+
+            // Expected output:
+            //  Feature     Change in NDCG@1    95% Confidence in the Mean Change in NDCG@1
+            //  Feature2    -0.2432             0.001762
+            //  Feature1    -0.05235            0.001116
+        }
+
+        private class Data
+        {
+            public float Label { get; set; }
+
+            public int GroupId { get; set; }
+
+            public float Feature1 { get; set; }
+
+            public float Feature2 { get; set; }
+        }
+
+        /// <summary>
+        /// Generate an enumerable of Data objects, creating the label as a simple
+        /// linear combination of the features.
+        /// </summary>
+        /// 
+        /// <param name="nExamples">The number of examples.</param>
+        /// 
+        /// <param name="bias">The bias, or offset, in the calculation of the label.
+        /// </param>
+        /// 
+        /// <param name="weight1">The weight to multiply the first feature with to
+        /// compute the label.</param>
+        /// 
+        /// <param name="weight2">The weight to multiply the second feature with to
+        /// compute the label.</param>
+        /// 
+        /// <param name="seed">The seed for generating feature values and label
+        /// noise.</param>
+        /// 
+        /// <returns>An enumerable of Data objects.</returns>
+        private static IEnumerable<Data> GenerateData(int nExamples = 10000,
+            double bias = 0, double weight1 = 1, double weight2 = 2, int seed = 1,
+                int groupSize = 5)
+        {
+            var rng = new Random(seed);
+            var max = bias + 4.5 * weight1 + 4.5 * weight2 + 0.5;
+            for (int i = 0; i < nExamples; i++)
+            {
+                var data = new Data
+                {
+                    GroupId = i / groupSize,
+                    Feature1 = (float)(rng.Next(10) * (rng.NextDouble() - 0.5)),
+                    Feature2 = (float)(rng.Next(10) * (rng.NextDouble() - 0.5)),
+                };
+
+                // Create a noisy label.
+                var value = (float)(bias + weight1 * data.Feature1 + weight2 *
+                    data.Feature2 + rng.NextDouble() - 0.5);
+                if (value < max / 3)
+                    data.Label = 0;
+                else if (value < 2 * max / 3)
+                    data.Label = 1;
+                else
+                    data.Label = 2;
+                yield return data;
+            }
+        }
+    }
+}
diff --git a/docs/samples/Microsoft.ML.Samples/Dynamic/Trainers/Regression/PermutationFeatureImportanceLoadFromDisk.cs b/docs/samples/Microsoft.ML.Samples/Dynamic/Trainers/Regression/PermutationFeatureImportanceLoadFromDisk.cs
new file mode 100644
index 0000000000..1a783b6c2a
--- /dev/null
+++ b/docs/samples/Microsoft.ML.Samples/Dynamic/Trainers/Regression/PermutationFeatureImportanceLoadFromDisk.cs
@@ -0,0 +1,132 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Microsoft.ML;
+using Microsoft.ML.Data;
+using Microsoft.ML.Trainers;
+
+namespace Samples.Dynamic.Trainers.Regression
+{
+    public static class PermutationFeatureImportanceLoadFromDisk
+    {
+        public static void Example()
+        {
+            // Create a new context for ML.NET operations. It can be used for
+            // exception tracking and logging, as a catalog of available operations
+            // and as the source of randomness.
+            var mlContext = new MLContext(seed: 1);
+
+            // Create sample data.
+            var samples = GenerateData();
+
+            // Load the sample data as an IDataView.
+            var data = mlContext.Data.LoadFromEnumerable(samples);
+
+            // Define a training pipeline that concatenates features into a vector,
+            // normalizes them, and then trains a linear model.
+            var featureColumns = new string[] { nameof(Data.Feature1),
+                nameof(Data.Feature2) };
+
+            var pipeline = mlContext.Transforms.Concatenate(
+                "Features",
+                featureColumns)
+                .Append(mlContext.Transforms.NormalizeMinMax("Features"))
+                .Append(mlContext.Regression.Trainers.Ols());
+
+            // Train the model and save to disk
+            var model0 = pipeline.Fit(data);
+            var modelPath = "./model0.zip";
+            mlContext.Model.Save(model0, data.Schema, modelPath);
+
+            // Load model
+            var model = mlContext.Model.Load(modelPath, out var schema);
+
+            // Transform Data
+            var transformedData = model.Transform(data);
+
+            // Extract the predictor.
+            var linearPredictor = (model as TransformerChain<ITransformer>).LastTransformer as RegressionPredictionTransformer<OlsModelParameters>;
+
+            // Compute the permutation metrics for the linear model using the
+            // normalized data.
+            var permutationMetrics = mlContext.Regression
+                .PermutationFeatureImportance(
+                linearPredictor, transformedData, permutationCount: 30);
+
+            // Now let's look at which features are most important to the model
+            // overall. Get the feature indices sorted by their impact on RMSE.
+            var sortedIndices = permutationMetrics
+                .Select((metrics, index) => new {
+                    index,
+                    metrics.RootMeanSquaredError
+                })
+
+                .OrderByDescending(feature => Math.Abs(
+                    feature.RootMeanSquaredError.Mean))
+
+                .Select(feature => feature.index);
+
+            Console.WriteLine("Feature\tModel Weight\tChange in RMSE\t95%" +
+                "Confidence in the Mean Change in RMSE");
+
+            var rmse = permutationMetrics.Select(x => x.RootMeanSquaredError)
+                .ToArray();
+
+            foreach (int i in sortedIndices)
+            {
+                Console.WriteLine("{0}\t{1:0.00}\t{2:G4}\t{3:G4}",
+                    featureColumns[i],
+                    linearPredictor.Model.Weights[i],
+                    rmse[i].Mean,
+                    1.96 * rmse[i].StandardError);
+            }
+
+            // Expected output:
+            //  Feature    Model Weight Change in RMSE  95% Confidence in the Mean Change in RMSE
+            //  Feature2        9.00        4.01        0.006723
+            //  Feature1        4.48        1.901       0.003235
+        }
+
+        private class Data
+        {
+            public float Label { get; set; }
+
+            public float Feature1 { get; set; }
+
+            public float Feature2 { get; set; }
+        }
+
+        /// <summary>
+        /// Generate an enumerable of Data objects, creating the label as a simple
+        /// linear combination of the features.
+        /// </summary>
+        /// <param name="nExamples">The number of examples.</param>
+        /// <param name="bias">The bias, or offset, in the calculation of the label.
+        /// </param>
+        /// <param name="weight1">The weight to multiply the first feature with to
+        /// compute the label.</param>
+        /// <param name="weight2">The weight to multiply the second feature with to
+        /// compute the label.</param>
+        /// <param name="seed">The seed for generating feature values and label
+        /// noise.</param>
+        /// <returns>An enumerable of Data objects.</returns>
+        private static IEnumerable<Data> GenerateData(int nExamples = 10000,
+            double bias = 0, double weight1 = 1, double weight2 = 2, int seed = 1)
+        {
+            var rng = new Random(seed);
+            for (int i = 0; i < nExamples; i++)
+            {
+                var data = new Data
+                {
+                    Feature1 = (float)(rng.Next(10) * (rng.NextDouble() - 0.5)),
+                    Feature2 = (float)(rng.Next(10) * (rng.NextDouble() - 0.5)),
+                };
+
+                // Create a noisy label.
+                data.Label = (float)(bias + weight1 * data.Feature1 + weight2 *
+                    data.Feature2 + rng.NextDouble() - 0.5);
+                yield return data;
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/Microsoft.ML.Data/Scorers/PredictionTransformer.cs b/src/Microsoft.ML.Data/Scorers/PredictionTransformer.cs
index a3b3ee10c1..53751614c2 100644
--- a/src/Microsoft.ML.Data/Scorers/PredictionTransformer.cs
+++ b/src/Microsoft.ML.Data/Scorers/PredictionTransformer.cs
@@ -2,22 +2,24 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
+using System;
 using System.IO;
+using System.Reflection;
 using Microsoft.ML;
 using Microsoft.ML.Data;
 using Microsoft.ML.Data.IO;
 using Microsoft.ML.Runtime;
 
-[assembly: LoadableClass(typeof(BinaryPredictionTransformer<IPredictorProducing<float>>), typeof(BinaryPredictionTransformer), null, typeof(SignatureLoadModel),
+[assembly: LoadableClass(typeof(ISingleFeaturePredictionTransformer<object>), typeof(BinaryPredictionTransformer), null, typeof(SignatureLoadModel),
     "", BinaryPredictionTransformer.LoaderSignature)]
 
-[assembly: LoadableClass(typeof(MulticlassPredictionTransformer<IPredictorProducing<VBuffer<float>>>), typeof(MulticlassPredictionTransformer), null, typeof(SignatureLoadModel),
+[assembly: LoadableClass(typeof(ISingleFeaturePredictionTransformer<object>), typeof(MulticlassPredictionTransformer), null, typeof(SignatureLoadModel),
     "", MulticlassPredictionTransformer.LoaderSignature)]
 
-[assembly: LoadableClass(typeof(RegressionPredictionTransformer<IPredictorProducing<float>>), typeof(RegressionPredictionTransformer), null, typeof(SignatureLoadModel),
+[assembly: LoadableClass(typeof(ISingleFeaturePredictionTransformer<object>), typeof(RegressionPredictionTransformer), null, typeof(SignatureLoadModel),
     "", RegressionPredictionTransformer.LoaderSignature)]
 
-[assembly: LoadableClass(typeof(RankingPredictionTransformer<IPredictorProducing<float>>), typeof(RankingPredictionTransformer), null, typeof(SignatureLoadModel),
+[assembly: LoadableClass(typeof(ISingleFeaturePredictionTransformer<object>), typeof(RankingPredictionTransformer), null, typeof(SignatureLoadModel),
     "", RankingPredictionTransformer.LoaderSignature)]
 
 [assembly: LoadableClass(typeof(AnomalyPredictionTransformer<IPredictorProducing<float>>), typeof(AnomalyPredictionTransformer), null, typeof(SignatureLoadModel),
@@ -28,6 +30,10 @@
 
 namespace Microsoft.ML.Data
 {
+    internal static class PredictionTransformerBase
+    {
+        internal const string DirModel = "Model";
+    }
 
     /// <summary>
     /// Base class for transformers with no feature column, or more than one feature columns.
@@ -44,7 +50,7 @@ public abstract class PredictionTransformerBase<TModel> : IPredictionTransformer
         private protected IPredictor ModelAsPredictor => (IPredictor)Model;
 
         [BestFriend]
-        private protected const string DirModel = "Model";
+        private protected const string DirModel = PredictionTransformerBase.DirModel;
         [BestFriend]
         private protected const string DirTransSchema = "TrainSchema";
         [BestFriend]
@@ -91,12 +97,27 @@ private protected PredictionTransformerBase(IHost host, ModelLoadContext ctx)
 
             // *** Binary format ***
             // model: prediction model.
-            // stream: empty data view that contains train schema.
-            // id of string: feature column.
 
             ctx.LoadModel<TModel, SignatureLoadModel>(host, out TModel model, DirModel);
             Model = model;
 
+            InitializeLogic(host, ctx);
+        }
+
+        [BestFriend]
+        private protected PredictionTransformerBase(IHost host, ModelLoadContext ctx, TModel model)
+        {
+            Host = host;
+            Model = model; // prediction model
+            InitializeLogic(host, ctx);
+        }
+
+        private void InitializeLogic(IHost host, ModelLoadContext ctx)
+        {
+            // *** Binary format ***
+            // stream: empty data view that contains train schema.
+            // id of string: feature column.
+
             // Clone the stream with the schema into memory.
             var ms = new MemoryStream();
             ctx.TryLoadBinaryStream(DirTransSchema, reader =>
@@ -215,6 +236,21 @@ private protected SingleFeaturePredictionTransformerBase(IHost host, ModelLoadCo
             BindableMapper = ScoreUtils.GetSchemaBindableMapper(Host, ModelAsPredictor);
         }
 
+        private protected SingleFeaturePredictionTransformerBase(IHost host, ModelLoadContext ctx, TModel model)
+            : base(host, ctx, model)
+        {
+            FeatureColumnName = ctx.LoadStringOrNull();
+
+            if (FeatureColumnName == null)
+                FeatureColumnType = null;
+            else if (!TrainSchema.TryGetColumnIndex(FeatureColumnName, out int col))
+                throw Host.ExceptSchemaMismatch(nameof(FeatureColumnName), "feature", FeatureColumnName);
+            else
+                FeatureColumnType = TrainSchema[col].Type;
+
+            BindableMapper = ScoreUtils.GetSchemaBindableMapper(Host, ModelAsPredictor);
+        }
+
         /// <summary>
         ///  Schema propagation for this prediction transformer.
         /// </summary>
@@ -348,14 +384,25 @@ internal BinaryPredictionTransformer(IHostEnvironment env, TModel model, DataVie
 
         internal BinaryPredictionTransformer(IHostEnvironment env, ModelLoadContext ctx)
             : base(Contracts.CheckRef(env, nameof(env)).Register(nameof(BinaryPredictionTransformer<TModel>)), ctx)
+        {
+            InitializationLogic(ctx, out Threshold, out ThresholdColumn);
+        }
+
+        internal BinaryPredictionTransformer(IHostEnvironment env, ModelLoadContext ctx, IHost host, TModel model)
+            : base(host, ctx, model)
+        {
+            InitializationLogic(ctx, out Threshold, out ThresholdColumn);
+        }
+
+        private void InitializationLogic(ModelLoadContext ctx, out float threshold, out string thresholdcolumn)
         {
             // *** Binary format ***
             // <base info>
             // float: scorer threshold
             // id of string: scorer threshold column
 
-            Threshold = ctx.Reader.ReadSingle();
-            ThresholdColumn = ctx.LoadString();
+            threshold = ctx.Reader.ReadSingle();
+            thresholdcolumn = ctx.LoadString();
             SetScorer();
         }
 
@@ -414,12 +461,24 @@ internal MulticlassPredictionTransformer(IHostEnvironment env, TModel model, Dat
 
         internal MulticlassPredictionTransformer(IHostEnvironment env, ModelLoadContext ctx)
             : base(Contracts.CheckRef(env, nameof(env)).Register(nameof(MulticlassPredictionTransformer<TModel>)), ctx)
+        {
+            InitializationLogic(ctx, out _trainLabelColumn);
+        }
+
+        internal MulticlassPredictionTransformer(IHostEnvironment env, ModelLoadContext ctx, IHost host, TModel model)
+            : base(host, ctx, model)
+        {
+
+            InitializationLogic(ctx, out _trainLabelColumn);
+        }
+
+        private void InitializationLogic(ModelLoadContext ctx, out string trainLabelColumn)
         {
             // *** Binary format ***
             // <base info>
             // id of string: train label column
 
-            _trainLabelColumn = ctx.LoadStringOrNull();
+            trainLabelColumn = ctx.LoadStringOrNull();
             SetScorer();
         }
 
@@ -475,6 +534,12 @@ internal RegressionPredictionTransformer(IHostEnvironment env, ModelLoadContext
             Scorer = GetGenericScorer();
         }
 
+        internal RegressionPredictionTransformer(IHostEnvironment env, ModelLoadContext ctx, IHost host, TModel model)
+            : base(host, ctx, model)
+        {
+            Scorer = GetGenericScorer();
+        }
+
         private protected override void SaveCore(ModelSaveContext ctx)
         {
             Contracts.AssertValue(ctx);
@@ -517,6 +582,12 @@ internal RankingPredictionTransformer(IHostEnvironment env, ModelLoadContext ctx
             Scorer = GetGenericScorer();
         }
 
+        internal RankingPredictionTransformer(IHostEnvironment env, ModelLoadContext ctx, IHost host, TModel model)
+            : base(host, ctx, model)
+        {
+            Scorer = GetGenericScorer();
+        }
+
         private protected override void SaveCore(ModelSaveContext ctx)
         {
             Contracts.AssertValue(ctx);
@@ -595,33 +666,109 @@ private static VersionInfo GetVersionInfo()
     internal static class BinaryPredictionTransformer
     {
         public const string LoaderSignature = "BinaryPredXfer";
+        private const string DirModel = PredictionTransformerBase.DirModel;
 
-        public static BinaryPredictionTransformer<IPredictorProducing<float>> Create(IHostEnvironment env, ModelLoadContext ctx)
-            => new BinaryPredictionTransformer<IPredictorProducing<float>>(env, ctx);
+        public static ISingleFeaturePredictionTransformer<object> Create(IHostEnvironment env, ModelLoadContext ctx)
+        {
+            // Load internal model to be used as TModel of BinaryPredictionTransformer<TModel>
+            var host = Contracts.CheckRef(env, nameof(env)).Register(nameof(BinaryPredictionTransformer<IPredictorProducing<float>>));
+            ctx.LoadModel<IPredictorProducing<float>, SignatureLoadModel>(host, out IPredictorProducing<float> model, DirModel);
+
+            Type generic = typeof(BinaryPredictionTransformer<>);
+            return (ISingleFeaturePredictionTransformer<object>) CreatePredictionTransformer.Create(env, ctx, host, model, generic);
+        }
     }
 
     internal static class MulticlassPredictionTransformer
     {
         public const string LoaderSignature = "MulticlassPredXfer";
+        private const string DirModel = PredictionTransformerBase.DirModel;
 
-        public static MulticlassPredictionTransformer<IPredictorProducing<VBuffer<float>>> Create(IHostEnvironment env, ModelLoadContext ctx)
-            => new MulticlassPredictionTransformer<IPredictorProducing<VBuffer<float>>>(env, ctx);
+        public static ISingleFeaturePredictionTransformer<object> Create(IHostEnvironment env, ModelLoadContext ctx)
+        {
+            // Load internal model to be used as TModel of MulticlassPredictionTransformer<TModel>
+            var host = Contracts.CheckRef(env, nameof(env)).Register(nameof(MulticlassPredictionTransformer<IPredictorProducing<VBuffer<float>>>));
+            ctx.LoadModel<IPredictorProducing<VBuffer<float>>, SignatureLoadModel>(host, out IPredictorProducing<VBuffer<float>> model, DirModel);
+
+            Type generic = typeof(MulticlassPredictionTransformer<>);
+            return (ISingleFeaturePredictionTransformer<object>) CreatePredictionTransformer.Create(env, ctx, host, model, generic);
+        }
     }
 
     internal static class RegressionPredictionTransformer
     {
         public const string LoaderSignature = "RegressionPredXfer";
+        private const string DirModel = PredictionTransformerBase.DirModel;
+
+        public static ISingleFeaturePredictionTransformer<object> Create(IHostEnvironment env, ModelLoadContext ctx)
+        {
+            // Load internal model to be used as TModel of RegressionPredictionTransformer<TModel>
+            var host = Contracts.CheckRef(env, nameof(env)).Register(nameof(RegressionPredictionTransformer<IPredictorProducing<float>>));
+            ctx.LoadModel<IPredictorProducing<float>, SignatureLoadModel>(host, out IPredictorProducing<float> model, DirModel);
 
-        public static RegressionPredictionTransformer<IPredictorProducing<float>> Create(IHostEnvironment env, ModelLoadContext ctx)
-            => new RegressionPredictionTransformer<IPredictorProducing<float>>(env, ctx);
+            Type generic = typeof(RegressionPredictionTransformer<>);
+            return (ISingleFeaturePredictionTransformer<object>) CreatePredictionTransformer.Create(env, ctx, host, model, generic);
+
+        }
     }
 
     internal static class RankingPredictionTransformer
     {
         public const string LoaderSignature = "RankingPredXfer";
+        private const string DirModel = PredictionTransformerBase.DirModel;
+
+        public static ISingleFeaturePredictionTransformer<object> Create(IHostEnvironment env, ModelLoadContext ctx)
+        {
+            // Load internal model to be used as TModel of RankingPredictionTransformer<TModel>
+            var host = Contracts.CheckRef(env, nameof(env)).Register(nameof(RankingPredictionTransformer<IPredictorProducing<float>>));
+            ctx.LoadModel<IPredictorProducing<float>, SignatureLoadModel>(host, out IPredictorProducing<float> model, DirModel);
+
+            Type generic = typeof(RankingPredictionTransformer<>);
+            return (ISingleFeaturePredictionTransformer<object>) CreatePredictionTransformer.Create(env, ctx, host, model, generic);
+        }
+    }
+
+    internal static class CreatePredictionTransformer
+    {
+        internal static object Create(IHostEnvironment env, ModelLoadContext ctx, IHost host, IPredictorProducing<float> model, Type generic)
+        {
+            // Create generic type of the prediction transformer using the correct TModel.
+            // Return an instance of that type, passing the previously loaded model to the constructor
+            Type[] genericTypeArgs = { model.GetType() };
+            Type constructed = generic.MakeGenericType(genericTypeArgs);
 
-        public static RankingPredictionTransformer<IPredictorProducing<float>> Create(IHostEnvironment env, ModelLoadContext ctx)
-            => new RankingPredictionTransformer<IPredictorProducing<float>>(env, ctx);
+            Type[] constructorArgs = {
+                typeof(IHostEnvironment),
+                typeof(ModelLoadContext),
+                typeof(IHost),
+                model.GetType()
+            };
+
+            var genericCtor = constructed.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, constructorArgs, null);
+            var genericInstance = genericCtor.Invoke(new object[] { env, ctx, host, model });
+
+            return genericInstance;
+        }
+
+        internal static object Create(IHostEnvironment env, ModelLoadContext ctx, IHost host, IPredictorProducing<VBuffer<float>> model, Type generic)
+        {
+            // Create generic type of the prediction transformer using the correct TModel.
+            // Return an instance of that type, passing the previously loaded model to the constructor
+            Type[] genericTypeArgs = { model.GetType() };
+            Type constructed = generic.MakeGenericType(genericTypeArgs);
+
+            Type[] constructorArgs = {
+                typeof(IHostEnvironment),
+                typeof(ModelLoadContext),
+                typeof(IHost),
+                model.GetType()
+            };
+
+            var genericCtor = constructed.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, constructorArgs, null);
+            var genericInstance = genericCtor.Invoke(new object[] { env, ctx, host, model });
+
+            return genericInstance;
+        }
     }
 
     internal static class AnomalyPredictionTransformer
diff --git a/test/Microsoft.ML.Functional.Tests/Explainability.cs b/test/Microsoft.ML.Functional.Tests/Explainability.cs
index 11729c3959..a63da1abea 100644
--- a/test/Microsoft.ML.Functional.Tests/Explainability.cs
+++ b/test/Microsoft.ML.Functional.Tests/Explainability.cs
@@ -6,6 +6,7 @@
 using Microsoft.ML.Functional.Tests.Datasets;
 using Microsoft.ML.RunTests;
 using Microsoft.ML.TestFramework;
+using Microsoft.ML.Trainers;
 using Microsoft.ML.Trainers.FastTree;
 using Xunit;
 using Xunit.Abstractions;
@@ -24,8 +25,10 @@ public Explainability(ITestOutputHelper output) : base(output)
         /// <summary>
         /// GlobalFeatureImportance: PFI can be used to compute global feature importance.
         /// </summary>
-        [Fact]
-        public void GlobalFeatureImportanceWithPermutationFeatureImportance()
+        [Theory]
+        [InlineData(true)]
+        [InlineData(false)]
+        public void GlobalFeatureImportanceWithPermutationFeatureImportance(bool saveModel)
         {
             var mlContext = new MLContext(seed: 1);
 
@@ -36,12 +39,38 @@ public void GlobalFeatureImportanceWithPermutationFeatureImportance()
             var pipeline = mlContext.Transforms.Concatenate("Features", HousingRegression.Features)
                 .Append(mlContext.Regression.Trainers.Sdca());
 
-            // Fit the pipeline and transform the data.
+            // Fit the pipeline
             var model = pipeline.Fit(data);
-            var transformedData = model.Transform(data);
+
+            IDataView transformedData;
+            RegressionPredictionTransformer<LinearRegressionModelParameters> linearPredictor;
+
+            if(saveModel)
+            {
+                ITransformer loadedModel;
+
+                // Load and save the model
+                var modelAndSchemaPath = GetOutputPath("TestFunctionalTestPFI.zip");
+                mlContext.Model.Save(model, data.Schema, modelAndSchemaPath);
+                loadedModel = mlContext.Model.Load(modelAndSchemaPath, out var schema);
+
+                // Transform the data
+                transformedData = loadedModel.Transform(data);
+
+                // Extract linear predictor
+                linearPredictor = (loadedModel as TransformerChain<ITransformer>).LastTransformer as RegressionPredictionTransformer<LinearRegressionModelParameters>;
+            }
+            else
+            {
+                // Transform the data
+                transformedData = model.Transform(data);
+
+                // Extract linear predictor
+                linearPredictor = model.LastTransformer;
+            }
 
             // Compute the permutation feature importance to look at global feature importance.
-            var permutationMetrics = mlContext.Regression.PermutationFeatureImportance(model.LastTransformer, transformedData);
+            var permutationMetrics = mlContext.Regression.PermutationFeatureImportance(linearPredictor, transformedData);
 
             // Make sure the correct number of features came back.
             Assert.Equal(HousingRegression.Features.Length, permutationMetrics.Length);
diff --git a/test/Microsoft.ML.Tests/PermutationFeatureImportanceTests.cs b/test/Microsoft.ML.Tests/PermutationFeatureImportanceTests.cs
index ac86a8703f..ac04e5452a 100644
--- a/test/Microsoft.ML.Tests/PermutationFeatureImportanceTests.cs
+++ b/test/Microsoft.ML.Tests/PermutationFeatureImportanceTests.cs
@@ -4,11 +4,13 @@
 
 using System;
 using System.Collections.Immutable;
+using System.IO;
 using System.Linq;
 using Microsoft.ML.Data;
 using Microsoft.ML.Internal.Utilities;
 using Microsoft.ML.RunTests;
 using Microsoft.ML.Trainers;
+using Microsoft.ML.Trainers.FastTree;
 using Xunit;
 using Xunit.Abstractions;
 
@@ -25,12 +27,28 @@ public PermutationFeatureImportanceTests(ITestOutputHelper output) : base(output
         /// <summary>
         /// Test PFI Regression for Dense Features
         /// </summary>
-        [Fact]
-        public void TestPfiRegressionOnDenseFeatures()
+        [Theory]
+        [InlineData(true)]
+        [InlineData(false)]
+        public void TestPfiRegressionOnDenseFeatures(bool saveModel)
         {
             var data = GetDenseDataset();
             var model = ML.Regression.Trainers.OnlineGradientDescent().Fit(data);
-            var pfi = ML.Regression.PermutationFeatureImportance(model, data);
+
+            ImmutableArray<RegressionMetricsStatistics> pfi;
+            if(saveModel)
+            {
+                var modelAndSchemaPath = GetOutputPath("TestPfiRegressionOnDenseFeatures.zip");
+                ML.Model.Save(model, data.Schema, modelAndSchemaPath);
+
+                var loadedModel = ML.Model.Load(modelAndSchemaPath, out var schema);
+                var castedModel = loadedModel as RegressionPredictionTransformer<LinearRegressionModelParameters>;
+                pfi = ML.Regression.PermutationFeatureImportance(castedModel, data);
+            }
+            else
+            {
+                pfi = ML.Regression.PermutationFeatureImportance(model, data);
+            }
 
             // Pfi Indices:
             // X1: 0
@@ -58,12 +76,30 @@ public void TestPfiRegressionOnDenseFeatures()
         /// <summary>
         /// Test PFI Regression Standard Deviation and Standard Error for Dense Features
         /// </summary>
-        [Fact]
-        public void TestPfiRegressionStandardDeviationAndErrorOnDenseFeatures()
+        [Theory]
+        [InlineData(true)]
+        [InlineData(false)]
+        public void TestPfiRegressionStandardDeviationAndErrorOnDenseFeatures(bool saveModel)
         {
             var data = GetDenseDataset();
             var model = ML.Regression.Trainers.OnlineGradientDescent().Fit(data);
-            var pfi = ML.Regression.PermutationFeatureImportance(model, data, permutationCount: 20);
+
+            ImmutableArray<RegressionMetricsStatistics> pfi;
+
+            if(saveModel)
+            {
+                var modelAndSchemaPath = GetOutputPath("TestPfiRegressionStandardDeviationAndErrorOnDenseFeatures.zip");
+                ML.Model.Save(model, data.Schema, modelAndSchemaPath);
+
+                var loadedModel = ML.Model.Load(modelAndSchemaPath, out var schema);
+                var castedModel = loadedModel as RegressionPredictionTransformer<LinearRegressionModelParameters>;
+                pfi = ML.Regression.PermutationFeatureImportance(castedModel, data, permutationCount: 20);
+            }
+            else
+            {
+                pfi = ML.Regression.PermutationFeatureImportance(model, data, permutationCount: 20);
+            }
+
             // Keep the permutation count high so fluctuations are kept to a minimum
             //  but not high enough to slow down the tests
             //  (fluctuations lead to random test failures)
@@ -110,12 +146,28 @@ public void TestPfiRegressionStandardDeviationAndErrorOnDenseFeatures()
         /// <summary>
         /// Test PFI Regression for Sparse Features
         /// </summary>
-        [Fact]
-        public void TestPfiRegressionOnSparseFeatures()
+        [Theory]
+        [InlineData(true)]
+        [InlineData(false)]
+        public void TestPfiRegressionOnSparseFeatures(bool saveModel)
         {
             var data = GetSparseDataset();
             var model = ML.Regression.Trainers.OnlineGradientDescent().Fit(data);
-            var results = ML.Regression.PermutationFeatureImportance(model, data);
+
+            ImmutableArray<RegressionMetricsStatistics> results;
+            if(saveModel)
+            {
+                var modelAndSchemaPath = GetOutputPath("TestPfiRegressionOnSparseFeatures.zip");
+                ML.Model.Save(model, data.Schema, modelAndSchemaPath);
+
+                var loadedModel = ML.Model.Load(modelAndSchemaPath, out var schema);
+                var castedModel = loadedModel as RegressionPredictionTransformer<LinearRegressionModelParameters>;
+                results = ML.Regression.PermutationFeatureImportance(castedModel, data);
+            }
+            else
+            {
+                results = ML.Regression.PermutationFeatureImportance(model, data);
+            }
 
             // Pfi Indices:
             // X1: 0
@@ -227,12 +279,28 @@ public void TestPfiBinaryClassificationOnSparseFeatures()
         /// <summary>
         /// Test PFI Multiclass Classification for Dense Features
         /// </summary>
-        [Fact]
-        public void TestPfiMulticlassClassificationOnDenseFeatures()
+        [Theory]
+        [InlineData(true)]
+        [InlineData(false)]
+        public void TestPfiMulticlassClassificationOnDenseFeatures(bool saveModel)
         {
             var data = GetDenseDataset(TaskType.MulticlassClassification);
             var model = ML.MulticlassClassification.Trainers.LbfgsMaximumEntropy().Fit(data);
-            var pfi = ML.MulticlassClassification.PermutationFeatureImportance(model, data);
+
+            ImmutableArray<MulticlassClassificationMetricsStatistics> pfi;
+            if(saveModel)
+            {
+                var modelAndSchemaPath = GetOutputPath("TestPfiMulticlassClassificationOnDenseFeatures.zip");
+                ML.Model.Save(model, data.Schema, modelAndSchemaPath);
+
+                var loadedModel = ML.Model.Load(modelAndSchemaPath, out var schema);
+                var castedModel = loadedModel as MulticlassPredictionTransformer<MaximumEntropyModelParameters>;
+                pfi = ML.MulticlassClassification.PermutationFeatureImportance(castedModel, data);
+            }
+            else
+            {
+                pfi = ML.MulticlassClassification.PermutationFeatureImportance(model, data);
+            }
 
             // Pfi Indices:
             // X1: 0
@@ -264,14 +332,29 @@ public void TestPfiMulticlassClassificationOnDenseFeatures()
         /// <summary>
         /// Test PFI Multiclass Classification for Sparse Features
         /// </summary>
-        [Fact]
-        public void TestPfiMulticlassClassificationOnSparseFeatures()
+        [Theory]
+        [InlineData(true)]
+        [InlineData(false)]
+        public void TestPfiMulticlassClassificationOnSparseFeatures(bool saveModel)
         {
             var data = GetSparseDataset(TaskType.MulticlassClassification);
             var model = ML.MulticlassClassification.Trainers.LbfgsMaximumEntropy(
                 new LbfgsMaximumEntropyMulticlassTrainer.Options { MaximumNumberOfIterations = 1000 }).Fit(data);
 
-            var pfi = ML.MulticlassClassification.PermutationFeatureImportance(model, data);
+            ImmutableArray<MulticlassClassificationMetricsStatistics> pfi;
+            if(saveModel)
+            {
+                var modelAndSchemaPath = GetOutputPath("TestPfiMulticlassClassificationOnSparseFeatures.zip");
+                ML.Model.Save(model, data.Schema, modelAndSchemaPath);
+
+                var loadedModel = ML.Model.Load(modelAndSchemaPath, out var schema);
+                var castedModel = loadedModel as MulticlassPredictionTransformer<MaximumEntropyModelParameters>;
+                pfi = ML.MulticlassClassification.PermutationFeatureImportance(castedModel, data);
+            }
+            else
+            {
+                pfi = ML.MulticlassClassification.PermutationFeatureImportance(model, data);
+            }
 
             // Pfi Indices:
             // X1: 0
@@ -305,14 +388,31 @@ public void TestPfiMulticlassClassificationOnSparseFeatures()
 
         #region Ranking Tests
         /// <summary>
-        /// Test PFI Multiclass Classification for Dense Features
+        /// Test PFI Ranking Classification for Dense Features
         /// </summary>
-        [Fact]
-        public void TestPfiRankingOnDenseFeatures()
+        [Theory]
+        [InlineData(true)]
+        [InlineData(false)]
+        public void TestPfiRankingOnDenseFeatures(bool saveModel)
         {
             var data = GetDenseDataset(TaskType.Ranking);
             var model = ML.Ranking.Trainers.FastTree().Fit(data);
-            var pfi = ML.Ranking.PermutationFeatureImportance(model, data);
+
+            ImmutableArray<RankingMetricsStatistics> pfi;
+            if(saveModel)
+            {
+                var modelAndSchemaPath = GetOutputPath("TestPfiRankingOnDenseFeatures.zip");
+                ML.Model.Save(model, data.Schema, modelAndSchemaPath);
+
+                var loadedModel = ML.Model.Load(modelAndSchemaPath, out var schema);
+                var castedModel = loadedModel as RankingPredictionTransformer<FastTreeRankingModelParameters>;
+                pfi = ML.Ranking.PermutationFeatureImportance(castedModel, data);
+            }
+            else
+            {
+                pfi = ML.Ranking.PermutationFeatureImportance(model, data);
+            }
+
 
             // Pfi Indices:
             // X1: 0 // For Ranking, this column won't result in misorderings
@@ -335,15 +435,32 @@ public void TestPfiRankingOnDenseFeatures()
             Done();
         }
 
+
         /// <summary>
         /// Test PFI Multiclass Classification for Sparse Features
         /// </summary>
-        [Fact]
-        public void TestPfiRankingOnSparseFeatures()
+        [Theory]
+        [InlineData(true)]
+        [InlineData(false)]
+        public void TestPfiRankingOnSparseFeatures(bool saveModel)
         {
             var data = GetSparseDataset(TaskType.Ranking);
             var model = ML.Ranking.Trainers.FastTree().Fit(data);
-            var pfi = ML.Ranking.PermutationFeatureImportance(model, data);
+
+            ImmutableArray<RankingMetricsStatistics> pfi;
+            if(saveModel)
+            {
+                var modelAndSchemaPath = GetOutputPath("TestPfiRankingOnSparseFeatures.zip");
+                ML.Model.Save(model, data.Schema, modelAndSchemaPath);
+
+                var loadedModel = ML.Model.Load(modelAndSchemaPath, out var schema);
+                var castedModel = loadedModel as RankingPredictionTransformer<FastTreeRankingModelParameters>;
+                pfi = ML.Ranking.PermutationFeatureImportance(castedModel, data);
+            }
+            else
+            {
+                pfi = ML.Ranking.PermutationFeatureImportance(model, data);
+            }
 
             // Pfi Indices:
             // X1: 0
diff --git a/test/Microsoft.ML.Tests/TrainerEstimators/LbfgsTests.cs b/test/Microsoft.ML.Tests/TrainerEstimators/LbfgsTests.cs
index 1174c87aca..f80ee68d2d 100644
--- a/test/Microsoft.ML.Tests/TrainerEstimators/LbfgsTests.cs
+++ b/test/Microsoft.ML.Tests/TrainerEstimators/LbfgsTests.cs
@@ -125,8 +125,8 @@ public void TestLRWithStats()
             using (var fs = File.OpenRead(modelAndSchemaPath))
                 transformerChain = ML.Model.Load(fs, out var schema);
 
-            var lastTransformer = ((TransformerChain<ITransformer>)transformerChain).LastTransformer as BinaryPredictionTransformer<IPredictorProducing<float>>;
-            var model = lastTransformer.Model as ParameterMixingCalibratedModelParameters<IPredictorProducing<float>, ICalibrator>;
+            var lastTransformer = ((TransformerChain<ITransformer>)transformerChain).LastTransformer as BinaryPredictionTransformer<ParameterMixingCalibratedModelParameters<IPredictorProducing<float>, ICalibrator>>;
+            var model = lastTransformer.Model;
 
             linearModel = model.SubModel as LinearBinaryModelParameters;
 
@@ -215,8 +215,8 @@ public void TestMLRWithStats()
             using (var fs = File.OpenRead(modelAndSchemaPath))
                 transformerChain = ML.Model.Load(fs, out var schema);
 
-            var lastTransformer = ((TransformerChain<ITransformer>)transformerChain).LastTransformer as MulticlassPredictionTransformer<IPredictorProducing<VBuffer<float>>>;
-            model = lastTransformer.Model as MaximumEntropyModelParameters;
+            var lastTransformer = ((TransformerChain<ITransformer>)transformerChain).LastTransformer as MulticlassPredictionTransformer<MaximumEntropyModelParameters>;
+            model = lastTransformer.Model;
 
             validateStats(model);