2
2
using System . Collections . Generic ;
3
3
using Microsoft . ML . Data ;
4
4
using Microsoft . ML . Trainers ;
5
+ using static Microsoft . ML . SamplesUtils . DatasetUtils ;
5
6
6
7
namespace Microsoft . ML . Samples . Dynamic
7
8
{
8
- public class MatrixFactorizationExample
9
+ public partial class MatrixFactorizationExample
9
10
{
10
- // The following variables defines the shape of a matrix. Its shape is _synthesizedMatrixRowCount-by-_synthesizedMatrixColumnCount.
11
- // Because in ML.NET key type's minimal value is zero, the first row index is always zero in C# data structure (e.g., MatrixColumnIndex=0
12
- // and MatrixRowIndex=0 in MatrixElement below specifies the value at the upper-left corner in the training matrix). If user's row index
13
- // starts with 1, their row index 1 would be mapped to the 2nd row in matrix factorization module and their first row may contain no values.
14
- // This behavior is also true to column index.
15
- const int _synthesizedMatrixFirstColumnIndex = 1 ;
16
- const int _synthesizedMatrixFirstRowIndex = 1 ;
17
- const int _synthesizedMatrixColumnCount = 60 ;
18
- const int _synthesizedMatrixRowCount = 100 ;
19
-
20
- // A data structure used to encode a single value in matrix
21
- internal class MatrixElement
22
- {
23
- // Matrix column index is at most _synthesizedMatrixColumnCount + _synthesizedMatrixFirstColumnIndex.
24
- [ KeyType ( Count = _synthesizedMatrixColumnCount + _synthesizedMatrixFirstColumnIndex ) ]
25
- public uint MatrixColumnIndex ;
26
- // Matrix row index is at most _synthesizedMatrixRowCount + _synthesizedMatrixFirstRowIndex.
27
- [ KeyType ( Count = _synthesizedMatrixRowCount + _synthesizedMatrixFirstRowIndex ) ]
28
- public uint MatrixRowIndex ;
29
- // The value at the column MatrixColumnIndex and row MatrixRowIndex.
30
- public float Value ;
31
- }
32
-
33
- // A data structure used to encode prediction result. Comparing with MatrixElement, The field Value in MatrixElement is
34
- // renamed to Score because Score is the default name of matrix factorization's output.
35
- internal class MatrixElementForScore
36
- {
37
- [ KeyType ( Count = _synthesizedMatrixColumnCount + _synthesizedMatrixFirstColumnIndex ) ]
38
- public uint MatrixColumnIndex ;
39
- [ KeyType ( Count = _synthesizedMatrixRowCount + _synthesizedMatrixFirstRowIndex ) ]
40
- public uint MatrixRowIndex ;
41
- public float Score ;
42
- }
43
11
44
12
// This example first creates in-memory data and then use it to train a matrix factorization model. Afterward, quality metrics are reported.
45
- public static void MatrixFactorizationInMemoryData ( )
13
+ public static void MatrixFactorizationWithOptions ( )
46
14
{
47
- // Create an in-memory matrix as a list of tuples (column index, row index, value).
48
- var dataMatrix = new List < MatrixElement > ( ) ;
49
- for ( uint i = _synthesizedMatrixFirstColumnIndex ; i < _synthesizedMatrixFirstColumnIndex + _synthesizedMatrixColumnCount ; ++ i )
50
- for ( uint j = _synthesizedMatrixFirstRowIndex ; j < _synthesizedMatrixFirstRowIndex + _synthesizedMatrixRowCount ; ++ j )
51
- dataMatrix . Add ( new MatrixElement ( ) { MatrixColumnIndex = i , MatrixRowIndex = j , Value = ( i + j ) % 5 } ) ;
52
-
53
15
// Create a new context for ML.NET operations. It can be used for exception tracking and logging,
54
16
// as a catalog of available operations and as the source of randomness.
55
17
var mlContext = new MLContext ( seed : 0 , conc : 1 ) ;
56
18
19
+ // Get a small in-memory dataset.
20
+ var data = GetRecommendationData ( ) ;
21
+
57
22
// Convert the in-memory matrix into an IDataView so that ML.NET components can consume it.
58
- var dataView = mlContext . Data . ReadFromEnumerable ( dataMatrix ) ;
23
+ var dataView = mlContext . Data . ReadFromEnumerable ( data ) ;
59
24
60
25
// Create a matrix factorization trainer which may consume "Value" as the training label, "MatrixColumnIndex" as the
61
26
// matrix's column index, and "MatrixRowIndex" as the matrix's row index. Here nameof(...) is used to extract field
62
27
// names' in MatrixElement class.
63
-
64
28
var options = new MatrixFactorizationTrainer . Options
65
29
{
66
30
MatrixColumnIndexColumnName = nameof ( MatrixElement . MatrixColumnIndex ) ,
67
31
MatrixRowIndexColumnName = nameof ( MatrixElement . MatrixRowIndex ) ,
68
32
LabelColumnName = nameof ( MatrixElement . Value ) ,
69
33
NumIterations = 10 ,
70
34
NumThreads = 1 ,
71
- K = 32 ,
35
+ ApproximationRank = 32 ,
36
+ LearningRate = 0.3
72
37
} ;
73
38
74
39
var pipeline = mlContext . Recommendation ( ) . Trainers . MatrixFactorization ( options ) ;
@@ -84,11 +49,11 @@ public static void MatrixFactorizationInMemoryData()
84
49
label : nameof ( MatrixElement . Value ) , score : nameof ( MatrixElementForScore . Score ) ) ;
85
50
86
51
// Print out some metrics for checking the model's quality.
87
- Console . WriteLine ( $ "L1 - { metrics . L1 } ") ;
88
- Console . WriteLine ( $ "L2 - { metrics . L2 } ") ;
89
- Console . WriteLine ( $ "LossFunction - { metrics . LossFn } ") ;
90
- Console . WriteLine ( $ "RMS - { metrics . Rms } ") ;
91
- Console . WriteLine ( $ "RSquared - { metrics . RSquared } ") ;
52
+ Console . WriteLine ( $ "L1 - { metrics . L1 } ") ; // 0.16375
53
+ Console . WriteLine ( $ "L2 - { metrics . L2 } ") ; // 0.04407
54
+ Console . WriteLine ( $ "LossFunction - { metrics . LossFn } ") ; // 0.04407
55
+ Console . WriteLine ( $ "RMS - { metrics . Rms } ") ; // 0.2099
56
+ Console . WriteLine ( $ "RSquared - { metrics . RSquared } ") ; // 0.97797
92
57
93
58
// Create two two entries for making prediction. Of course, the prediction value, Score, is unknown so it can be anything
94
59
// (here we use Score=0 and it will be overwritten by the true prediction). If any of row and column indexes are out-of-range
@@ -101,8 +66,10 @@ public static void MatrixFactorizationInMemoryData()
101
66
var testDataView = mlContext . Data . ReadFromEnumerable ( testMatrix ) ;
102
67
103
68
// Feed the test data into the model and then iterate through all predictions.
104
- foreach ( var pred in mlContext . CreateEnumerable < MatrixElementForScore > ( testDataView , false ) )
105
- Console . WriteLine ( $ "Predicted value at row { pred . MatrixRowIndex } and column { pred . MatrixColumnIndex } is { pred . Score } ") ;
69
+ foreach ( var pred in mlContext . CreateEnumerable < MatrixElementForScore > ( model . Transform ( testDataView ) , false ) )
70
+ Console . WriteLine ( $ "Predicted value at row { pred . MatrixRowIndex - 1 } and column { pred . MatrixColumnIndex - 1 } is { pred . Score } ") ;
71
+ // Predicted value at row 7 and column 1 is 2.828761
72
+ // Predicted value at row 6 and column 3 is 3.642226
106
73
}
107
74
}
108
75
}
0 commit comments