4
4
using Microsoft . ML . StaticPipe ;
5
5
using System ;
6
6
using System . Collections . Generic ;
7
+ using System . Linq ;
7
8
8
9
namespace Microsoft . ML . Samples . Static
9
10
{
@@ -23,11 +24,9 @@ private class NativeExample
23
24
[ VectorType ( _featureVectorLength ) ]
24
25
public float [ ] Features ;
25
26
[ ColumnName ( "Label" ) ]
26
- // One of "AA", "BB", "CC", and "DD".
27
27
public string Label ;
28
28
public uint LabelIndex ;
29
- // One of "AA", "BB", "CC", and "DD".
30
- public string PredictedLabel ;
29
+ public uint PredictedLabelIndex ;
31
30
[ VectorType ( 4 ) ]
32
31
// The probabilities of being "AA", "BB", "CC", and "DD".
33
32
public float [ ] Scores ;
@@ -68,15 +67,15 @@ private static List<NativeExample> GenerateRandomExamples(int count)
68
67
69
68
// The following three attributes are just placeholder for storing prediction results.
70
69
example . LabelIndex = default ;
71
- example . PredictedLabel = null ;
70
+ example . PredictedLabelIndex = default ;
72
71
example . Scores = new float [ 4 ] ;
73
72
74
73
examples . Add ( example ) ;
75
74
}
76
75
return examples ;
77
76
}
78
77
79
- public static void MultiClassLightGbmStaticPipelineWithInMemoryData ( )
78
+ public void MultiClassLightGbmStaticPipelineWithInMemoryData ( )
80
79
{
81
80
// Create a general context for ML.NET operations. It can be used for exception tracking and logging,
82
81
// as a catalog of available operations and as the source of randomness.
@@ -112,11 +111,10 @@ public static void MultiClassLightGbmStaticPipelineWithInMemoryData()
112
111
r . Label ,
113
112
// Labels are converted to keys when training LightGBM so we convert it here again for calling evaluation function.
114
113
LabelIndex : r . Label . ToKey ( ) ,
115
- // Instance of ClassificationVectorData returned
114
+ // Used to compute metrics such as accuracy.
116
115
r . Predictions ,
117
- // ToValue() is used to get the original out from the class indexes computed by ToKey().
118
- // For example, if label "AA" is maped to index 0 via ToKey(), then ToValue() produces "AA" from 0.
119
- PredictedLabel : r . Predictions . predictedLabel . ToValue ( ) ,
116
+ // Assign a new name to predicted class index.
117
+ PredictedLabelIndex : r . Predictions . predictedLabel ,
120
118
// Assign a new name to class probabilities.
121
119
Scores : r . Predictions . score
122
120
) ) ;
@@ -135,26 +133,30 @@ public static void MultiClassLightGbmStaticPipelineWithInMemoryData()
135
133
var metrics = ctx . Evaluate ( prediction , r => r . LabelIndex , r => r . Predictions ) ;
136
134
137
135
// Check if metrics are resonable.
138
- Console . WriteLine ( metrics . AccuracyMacro ) ; // expected value: 0.863482146891263
139
- Console . WriteLine ( metrics . AccuracyMicro ) ; // expected value: 0.86309523809523814
136
+ Console . WriteLine ( "Macro accuracy: {0}, Micro accuracy: {1}." , 0.863482146891263 , 0.86309523809523814 ) ;
140
137
141
138
// Convert prediction in ML.NET format to native C# class.
142
139
var nativePredictions = new List < NativeExample > ( prediction . AsDynamic . AsEnumerable < NativeExample > ( mlContext , false ) ) ;
143
140
144
- // Check predicted label and class probabilities of second-first example.
145
- // If you see a label with LabelIndex 1, its means its probability is the 1st element in the Scores field.
146
- // For example, if "AA" is indexed by 1, "BB" indexed by 2, "CC" indexed by 3, and "DD" indexed by 4, Scores is
147
- // ["AA" probability, "BB" probability, "CC" probability, "DD" probability].
141
+ // Get cchema object of the prediction. It contains metadata such as the mapping from predicted label index
142
+ // (e.g., 1) to its actual label (e.g., "AA").
143
+ var schema = prediction . AsDynamic . Schema ;
144
+
145
+ // Retrieve the mapping from labels to label indexes.
146
+ var labelBuffer = new VBuffer < ReadOnlyMemory < char > > ( ) ;
147
+ schema [ nameof ( NativeExample . PredictedLabelIndex ) ] . Metadata . GetValue ( "KeyValues" , ref labelBuffer ) ;
148
+ var nativeLabels = labelBuffer . DenseValues ( ) . ToList ( ) ; // nativeLabels[nativePrediction.PredictedLabelIndex-1] is the original label indexed by nativePrediction.PredictedLabelIndex.
149
+
150
+ // Show prediction result for the 3rd example.
148
151
var nativePrediction = nativePredictions [ 2 ] ;
149
- var probAA = nativePrediction . Scores [ 0 ] ;
150
- var probBB = nativePrediction . Scores [ 1 ] ;
151
- var probCC = nativePrediction . Scores [ 2 ] ;
152
- var probDD = nativePrediction . Scores [ 3 ] ;
153
-
154
- Console . WriteLine ( probAA ) ; // expected value: 0.922597349
155
- Console . WriteLine ( probBB ) ; // expected value: 0.07508608
156
- Console . WriteLine ( probCC ) ; // expected value: 0.00221699756
157
- Console . WriteLine ( probDD ) ; // expected value: 9.95488E-05
152
+ Console . WriteLine ( "Our predicted label to this example is {0} with probability {1}" ,
153
+ nativeLabels [ ( int ) nativePrediction . PredictedLabelIndex - 1 ] ,
154
+ nativePrediction . Scores [ ( int ) nativePrediction . PredictedLabelIndex - 1 ] ) ;
155
+
156
+ var expectedProbabilities = new float [ ] { 0.922597349f , 0.07508608f , 0.00221699756f , 9.95488E-05f } ;
157
+ // Scores and nativeLabels are two parallel attributes; that is, Scores[i] is the probability of being nativeLabels[i].
158
+ for ( int i = 0 ; i < labelBuffer . Length ; ++ i )
159
+ Console . WriteLine ( "The probability of being class {0} is {1}." , nativeLabels [ i ] , nativePrediction . Scores [ i ] ) ;
158
160
}
159
161
}
160
162
}
0 commit comments