Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 11 additions & 13 deletions src/Microsoft.ML.Recommender/MatrixFactorizationTrainer.cs
Original file line numberDiff line numberDiff line change
Expand Up@@ -31,24 +31,19 @@ namespace Microsoft.ML.Trainers
/// and the value at the location specified by the two indexes. For an example data structure of a tuple, one can use:
/// </para>
/// <code language="csharp">
/// // The following variables defines the shape of a m-by-n matrix. The variable firstRowIndex indicates the integer that
/// // would be mapped to the first row index. If user data uses 0-based indices for rows, firstRowIndex can be set to 0.
/// // Similarly, for 1-based indices, firstRowIndex could be 1.
/// const int firstRowIndex = 1;
/// const int firstColumnIndex = 1;
/// // The following variables defines the shape of a m-by-n matrix. Indexes start with 0; that is, our indexing system
/// // is 0-based.
/// const int m = 60;
/// const int n = 100;
///
/// // A tuple of row index, column index, and rating. It specifies a value in the rating matrix.
/// class MatrixElement
/// {
/// // Matrix column index starts from firstColumnIndex and is at most firstColumnIndex+n-1.
/// // Contieuous=true means that all values from firstColumnIndex to firstColumnIndex+n-1 are allowed keys.
/// // [KeyType(Contiguous = true, Count = n, Min = firstColumnIndex)]
/// // public uint MatrixColumnIndex;
/// // Matrix row index starts from firstRowIndex and is at most firstRowIndex+m-1.
/// // Contieuous=true means that all values from firstRowIndex to firstRowIndex+m-1 are allowed keys.
/// [KeyType(Contiguous = true, Count = m, Min = firstRowIndex)]
/// // Matrix column index starts from 0 and is at most n-1.
/// [KeyType(n)]
/// public uint MatrixColumnIndex;
/// // Matrix row index starts from 0 and is at most m-1.
/// [KeyType(m)]
/// public uint MatrixRowIndex;
/// // The rating at the MatrixColumnIndex-th column and the MatrixRowIndex-th row.
/// public float Value;
Expand All@@ -65,7 +60,7 @@ namespace Microsoft.ML.Trainers
/// <i>R</i> is approximated by the product of <i>P</i>'s transpose and <i>Q</i>. This trainer implements
/// <a href='https://www.csie.ntu.edu.tw/~cjlin/papers/libmf/mf_adaptive_pakdd.pdf'>a stochastic gradient method</a> for finding <i>P</i>
/// and <i>Q</i> via minimizing the distance between<i> R</i> and the product of <i>P</i>'s transpose and Q.</para>.
/// <para>For users interested in the mathematical details, please see the references below.</para>
/// <para>The underlying library used in ML.NET matrix factorization can be found on <a href='https://github.com/cjlin1/libmf'>a Github repository</a>. For users interested in the mathematical details, please see the references below.</para>
/// <list type = 'bullet'>
/// <item>
/// <description><a href='https://www.csie.ntu.edu.tw/~cjlin/papers/libmf/libmf_journal.pdf' > A Fast Parallel Stochastic Gradient Method for Matrix Factorization in Shared Memory Systems</a></description>
Expand All@@ -76,6 +71,9 @@ namespace Microsoft.ML.Trainers
/// <item>
/// <description><a href='https://www.csie.ntu.edu.tw/~cjlin/papers/libmf/libmf_open_source.pdf' > LIBMF: A Library for Parallel Matrix Factorization in Shared-memory Systems</a></description>
/// </item>
/// <item>
/// <description><a href='https://www.csie.ntu.edu.tw/~cjlin/papers/one-class-mf/biased-mf-sdm-with-supp.pdf' > Selection of Negative Samples for One-class Matrix Factorization</a></description>
/// </item>
/// </list>
/// </remarks>
/// <example>
Expand Down
84 changes: 45 additions & 39 deletions src/Microsoft.ML.Recommender/SafeTrainingAndModelBuffer.cs
Original file line numberDiff line numberDiff line change
Expand Up@@ -17,31 +17,50 @@ namespace Microsoft.ML.Recommender.Internal
/// </summary>
internal sealed class SafeTrainingAndModelBuffer : IDisposable
{
[StructLayout(LayoutKind.Explicit)]
[StructLayout(LayoutKind.Sequential)]
private struct MFNode
{
[FieldOffset(0)]
/// <summary>
/// Row index.
/// </summary>
public int U;
[FieldOffset(4)]

/// <summary>
/// Column index;
/// </summary>
public int V;
[FieldOffset(8)]

/// <summary>
/// Matrix element's value at <see cref="U"/>-th row and <see cref="V"/>-th column.
/// </summary>
public float R;
}

[StructLayout(LayoutKind.Explicit)]
[StructLayout(LayoutKind.Sequential)]
private unsafe struct MFProblem
{
[FieldOffset(0)]
/// <summary>
/// Number of rows.
/// </summary>
public int M;
[FieldOffset(4)]

/// <summary>
/// Number of columns.
/// </summary>
public int N;
[FieldOffset(8)]

/// <summary>
/// Number of specified matrix elements in <see cref="R"/>.
/// </summary>
public long Nnz;
[FieldOffset(16)]

/// <summary>
/// Specified matrix elements.
/// </summary>
public MFNode* R;
}

[StructLayout(LayoutKind.Explicit)]
[StructLayout(LayoutKind.Sequential)]
private struct MFParameter
{
/// <summary>
Expand All@@ -58,130 +77,117 @@ private struct MFParameter
/// Fun 12 is solved by a coordinate descent method while other functions invoke
/// a stochastic gradient method.
/// </summary>
[FieldOffset(0)]
public int Fun;

/// <summary>
/// Rank of factor matrices.
/// </summary>
[FieldOffset(4)]
public int K;

/// <summary>
/// Number of threads which can be used for training.
/// </summary>
[FieldOffset(8)]
public int NrThreads;

/// <summary>
/// Number of blocks that the training matrix is divided into. The parallel stochastic gradient
/// method in LIBMF processes assigns each thread a block at one time. The ratings in one block
/// would be sequentially accessed (not randomaly accessed like standard stochastic gradient methods).
/// </summary>
[FieldOffset(12)]
public int NrBins;

/// <summary>
/// Number of training iteration. At one iteration, all values in the training matrix are roughly accessed once.
/// </summary>
[FieldOffset(16)]
public int NrIters;

/// <summary>
/// L1-norm regularization coefficient of left factor matrix.
/// </summary>
[FieldOffset(20)]
public float LambdaP1;

/// <summary>
/// L2-norm regularization coefficient of left factor matrix.
/// </summary>
[FieldOffset(24)]
public float LambdaP2;

/// <summary>
/// L1-norm regularization coefficient of right factor matrix.
/// </summary>
[FieldOffset(28)]
public float LambdaQ1;

/// <summary>
/// L2-norm regularization coefficient of right factor matrix.
/// </summary>
[FieldOffset(32)]
public float LambdaQ2;

/// <summary>
/// Learning rate of LIBMF's stochastic gradient method.
/// </summary>
[FieldOffset(36)]
public float Eta;

/// <summary>
/// Coefficient of loss function on unobserved entries in the training matrix. It's used only with fun=12.
/// </summary>
[FieldOffset(40)]
public float Alpha;

/// <summary>
/// Desired value of unobserved entries in the training matrix. It's used only with fun=12.
/// </summary>
[FieldOffset(44)]
public float C;

/// <summary>
/// Specify if the factor matrices should be non-negative.
/// </summary>
[FieldOffset(48)]
public int DoNmf;
public byte DoNmf;

/// <summary>
/// Set to true so that LIBMF may produce less information to STDOUT.
/// </summary>
[FieldOffset(52)]
public int Quiet;
public byte Quiet;

/// <summary>
/// Set to false so that LIBMF may reuse and modifiy the data passed in.
/// </summary>
[FieldOffset(56)]
public int CopyData;
public byte CopyData;
}

[StructLayout(LayoutKind.Explicit)]
[StructLayout(LayoutKind.Sequential)]
private unsafe struct MFModel
{
[FieldOffset(0)]
/// <summary>
/// See <see cref="MFParameter.Fun"/>.
/// </summary>
public int Fun;

/// <summary>
/// Number of rows in the training matrix.
/// </summary>
[FieldOffset(4)]
public int M;

/// <summary>
/// Number of columns in the training matrix.
/// </summary>
[FieldOffset(8)]
public int N;

/// <summary>
/// Rank of factor matrices.
/// </summary>
[FieldOffset(12)]
public int K;

/// <summary>
/// Average value in the training matrix.
/// </summary>
[FieldOffset(16)]
public float B;

/// <summary>
/// Left factor matrix. Its shape is M-by-K stored in row-major format.
/// </summary>
[FieldOffset(24)] // pointer is 8-byte on 64-bit machine.
public float* P;

/// <summary>
/// Right factor matrix. Its shape is N-by-K stored in row-major format.
/// </summary>
[FieldOffset(32)] // pointer is 8-byte on 64-bit machine.
public float* Q;
}

Expand DownExpand Up@@ -223,9 +229,9 @@ public SafeTrainingAndModelBuffer(IHostEnvironment env, int fun, int k, int nrTh
_mfParam.Eta = (float)eta;
_mfParam.Alpha = (float)alpha;
_mfParam.C = (float)c;
_mfParam.DoNmf = doNmf ? 1 : 0;
_mfParam.Quiet = quiet ? 1 : 0;
_mfParam.CopyData = copyData ? 1 : 0;
_mfParam.DoNmf = doNmf ? (byte)1 : (byte)0;
_mfParam.Quiet = quiet ? (byte)1 : (byte)0;
_mfParam.CopyData = copyData ? (byte)1 : (byte)0;
}

~SafeTrainingAndModelBuffer()
Expand Down
21 changes: 17 additions & 4 deletions src/Native/MatrixFactorizationNative/CMakeLists.txt
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,25 @@
project (MatrixFactorizationNative)
add_definitions(-D_SCL_SECURE_NO_WARNINGS)
add_definitions(-DUSEOMP)
add_definitions(-DUSESSE)

include_directories(libmf)

set(SOURCES
UnmanagedMemory.cpp
libmf/mf.cpp
)
if(UNIX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -O3 -pthread -std=c++0x -march=native")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fopenmp")
if (APPLE)
include_directories("/usr/local/opt/libomp/include")
link_directories("/usr/local/opt/libomp/lib")
endif()
endif()

if(WIN32)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4 /nologo /O2 /EHsc /D \"_CRT_SECURE_NO_DEPRECATE\" /openmp")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}")
endif()

set(SOURCES UnmanagedMemory.cpp libmf/mf.cpp)

if(NOT WIN32)
list(APPEND SOURCES ${VERSION_FILE_PATH})
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 11 additions & 13 deletions src/Microsoft.ML.Recommender/MatrixFactorizationTrainer.cs
Original file line numberDiff line numberDiff line change
Expand Up@@ -31,24 +31,19 @@ namespace Microsoft.ML.Trainers
/// and the value at the location specified by the two indexes. For an example data structure of a tuple, one can use:
/// </para>
/// <code language="csharp">
/// // The following variables defines the shape of a m-by-n matrix. The variable firstRowIndex indicates the integer that
/// // would be mapped to the first row index. If user data uses 0-based indices for rows, firstRowIndex can be set to 0.
/// // Similarly, for 1-based indices, firstRowIndex could be 1.
/// const int firstRowIndex = 1;
/// const int firstColumnIndex = 1;
/// // The following variables defines the shape of a m-by-n matrix. Indexes start with 0; that is, our indexing system
/// // is 0-based.
/// const int m = 60;
/// const int n = 100;
///
/// // A tuple of row index, column index, and rating. It specifies a value in the rating matrix.
/// class MatrixElement
/// {
/// // Matrix column index starts from firstColumnIndex and is at most firstColumnIndex+n-1.
/// // Contieuous=true means that all values from firstColumnIndex to firstColumnIndex+n-1 are allowed keys.
/// // [KeyType(Contiguous = true, Count = n, Min = firstColumnIndex)]
/// // public uint MatrixColumnIndex;
/// // Matrix row index starts from firstRowIndex and is at most firstRowIndex+m-1.
/// // Contieuous=true means that all values from firstRowIndex to firstRowIndex+m-1 are allowed keys.
/// [KeyType(Contiguous = true, Count = m, Min = firstRowIndex)]
/// // Matrix column index starts from 0 and is at most n-1.
/// [KeyType(n)]
/// public uint MatrixColumnIndex;
/// // Matrix row index starts from 0 and is at most m-1.
/// [KeyType(m)]
/// public uint MatrixRowIndex;
/// // The rating at the MatrixColumnIndex-th column and the MatrixRowIndex-th row.
/// public float Value;
Expand All@@ -65,7 +60,7 @@ namespace Microsoft.ML.Trainers
/// <i>R</i> is approximated by the product of <i>P</i>'s transpose and <i>Q</i>. This trainer implements
/// <a href='https://www.csie.ntu.edu.tw/~cjlin/papers/libmf/mf_adaptive_pakdd.pdf'>a stochastic gradient method</a> for finding <i>P</i>
/// and <i>Q</i> via minimizing the distance between<i> R</i> and the product of <i>P</i>'s transpose and Q.</para>.
/// <para>For users interested in the mathematical details, please see the references below.</para>
/// <para>The underlying library used in ML.NET matrix factorization can be found on <a href='https://github.com/cjlin1/libmf'>a Github repository</a>. For users interested in the mathematical details, please see the references below.</para>
/// <list type = 'bullet'>
/// <item>
/// <description><a href='https://www.csie.ntu.edu.tw/~cjlin/papers/libmf/libmf_journal.pdf' > A Fast Parallel Stochastic Gradient Method for Matrix Factorization in Shared Memory Systems</a></description>
Expand All@@ -76,6 +71,9 @@ namespace Microsoft.ML.Trainers
/// <item>
/// <description><a href='https://www.csie.ntu.edu.tw/~cjlin/papers/libmf/libmf_open_source.pdf' > LIBMF: A Library for Parallel Matrix Factorization in Shared-memory Systems</a></description>
/// </item>
/// <item>
/// <description><a href='https://www.csie.ntu.edu.tw/~cjlin/papers/one-class-mf/biased-mf-sdm-with-supp.pdf' > Selection of Negative Samples for One-class Matrix Factorization</a></description>
/// </item>
/// </list>
/// </remarks>
/// <example>
Expand Down
84 changes: 45 additions & 39 deletions src/Microsoft.ML.Recommender/SafeTrainingAndModelBuffer.cs
Original file line numberDiff line numberDiff line change
Expand Up@@ -17,31 +17,50 @@ namespace Microsoft.ML.Recommender.Internal
/// </summary>
internal sealed class SafeTrainingAndModelBuffer : IDisposable
{
[StructLayout(LayoutKind.Explicit)]
[StructLayout(LayoutKind.Sequential)]
private struct MFNode
{
[FieldOffset(0)]
/// <summary>
/// Row index.
/// </summary>
public int U;
[FieldOffset(4)]

/// <summary>
/// Column index;
/// </summary>
public int V;
[FieldOffset(8)]

/// <summary>
/// Matrix element's value at <see cref="U"/>-th row and <see cref="V"/>-th column.
/// </summary>
public float R;
}

[StructLayout(LayoutKind.Explicit)]
[StructLayout(LayoutKind.Sequential)]
private unsafe struct MFProblem
{
[FieldOffset(0)]
/// <summary>
/// Number of rows.
/// </summary>
public int M;
[FieldOffset(4)]

/// <summary>
/// Number of columns.
/// </summary>
public int N;
[FieldOffset(8)]

/// <summary>
/// Number of specified matrix elements in <see cref="R"/>.
/// </summary>
public long Nnz;
[FieldOffset(16)]

/// <summary>
/// Specified matrix elements.
/// </summary>
public MFNode* R;
}

[StructLayout(LayoutKind.Explicit)]
[StructLayout(LayoutKind.Sequential)]
private struct MFParameter
{
/// <summary>
Expand All@@ -58,130 +77,117 @@ private struct MFParameter
/// Fun 12 is solved by a coordinate descent method while other functions invoke
/// a stochastic gradient method.
/// </summary>
[FieldOffset(0)]
public int Fun;

/// <summary>
/// Rank of factor matrices.
/// </summary>
[FieldOffset(4)]
public int K;

/// <summary>
/// Number of threads which can be used for training.
/// </summary>
[FieldOffset(8)]
public int NrThreads;

/// <summary>
/// Number of blocks that the training matrix is divided into. The parallel stochastic gradient
/// method in LIBMF processes assigns each thread a block at one time. The ratings in one block
/// would be sequentially accessed (not randomaly accessed like standard stochastic gradient methods).
/// </summary>
[FieldOffset(12)]
public int NrBins;

/// <summary>
/// Number of training iteration. At one iteration, all values in the training matrix are roughly accessed once.
/// </summary>
[FieldOffset(16)]
public int NrIters;

/// <summary>
/// L1-norm regularization coefficient of left factor matrix.
/// </summary>
[FieldOffset(20)]
public float LambdaP1;

/// <summary>
/// L2-norm regularization coefficient of left factor matrix.
/// </summary>
[FieldOffset(24)]
public float LambdaP2;

/// <summary>
/// L1-norm regularization coefficient of right factor matrix.
/// </summary>
[FieldOffset(28)]
public float LambdaQ1;

/// <summary>
/// L2-norm regularization coefficient of right factor matrix.
/// </summary>
[FieldOffset(32)]
public float LambdaQ2;

/// <summary>
/// Learning rate of LIBMF's stochastic gradient method.
/// </summary>
[FieldOffset(36)]
public float Eta;

/// <summary>
/// Coefficient of loss function on unobserved entries in the training matrix. It's used only with fun=12.
/// </summary>
[FieldOffset(40)]
public float Alpha;

/// <summary>
/// Desired value of unobserved entries in the training matrix. It's used only with fun=12.
/// </summary>
[FieldOffset(44)]
public float C;

/// <summary>
/// Specify if the factor matrices should be non-negative.
/// </summary>
[FieldOffset(48)]
public int DoNmf;
public byte DoNmf;

/// <summary>
/// Set to true so that LIBMF may produce less information to STDOUT.
/// </summary>
[FieldOffset(52)]
public int Quiet;
public byte Quiet;

/// <summary>
/// Set to false so that LIBMF may reuse and modifiy the data passed in.
/// </summary>
[FieldOffset(56)]
public int CopyData;
public byte CopyData;
}

[StructLayout(LayoutKind.Explicit)]
[StructLayout(LayoutKind.Sequential)]
private unsafe struct MFModel
{
[FieldOffset(0)]
/// <summary>
/// See <see cref="MFParameter.Fun"/>.
/// </summary>
public int Fun;

/// <summary>
/// Number of rows in the training matrix.
/// </summary>
[FieldOffset(4)]
public int M;

/// <summary>
/// Number of columns in the training matrix.
/// </summary>
[FieldOffset(8)]
public int N;

/// <summary>
/// Rank of factor matrices.
/// </summary>
[FieldOffset(12)]
public int K;

/// <summary>
/// Average value in the training matrix.
/// </summary>
[FieldOffset(16)]
public float B;

/// <summary>
/// Left factor matrix. Its shape is M-by-K stored in row-major format.
/// </summary>
[FieldOffset(24)] // pointer is 8-byte on 64-bit machine.
public float* P;

/// <summary>
/// Right factor matrix. Its shape is N-by-K stored in row-major format.
/// </summary>
[FieldOffset(32)] // pointer is 8-byte on 64-bit machine.
public float* Q;
}

Expand DownExpand Up@@ -223,9 +229,9 @@ public SafeTrainingAndModelBuffer(IHostEnvironment env, int fun, int k, int nrTh
_mfParam.Eta = (float)eta;
_mfParam.Alpha = (float)alpha;
_mfParam.C = (float)c;
_mfParam.DoNmf = doNmf ? 1 : 0;
_mfParam.Quiet = quiet ? 1 : 0;
_mfParam.CopyData = copyData ? 1 : 0;
_mfParam.DoNmf = doNmf ? (byte)1 : (byte)0;
_mfParam.Quiet = quiet ? (byte)1 : (byte)0;
_mfParam.CopyData = copyData ? (byte)1 : (byte)0;
}

~SafeTrainingAndModelBuffer()
Expand Down
21 changes: 17 additions & 4 deletions src/Native/MatrixFactorizationNative/CMakeLists.txt
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,25 @@
project (MatrixFactorizationNative)
add_definitions(-D_SCL_SECURE_NO_WARNINGS)
add_definitions(-DUSEOMP)
add_definitions(-DUSESSE)

include_directories(libmf)

set(SOURCES
UnmanagedMemory.cpp
libmf/mf.cpp
)
if(UNIX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -O3 -pthread -std=c++0x -march=native")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fopenmp")
if (APPLE)
include_directories("/usr/local/opt/libomp/include")
link_directories("/usr/local/opt/libomp/lib")
endif()
endif()

if(WIN32)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4 /nologo /O2 /EHsc /D \"_CRT_SECURE_NO_DEPRECATE\" /openmp")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}")
endif()

set(SOURCES UnmanagedMemory.cpp libmf/mf.cpp)

if(NOT WIN32)
list(APPEND SOURCES ${VERSION_FILE_PATH})
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 11 additions & 13 deletions src/Microsoft.ML.Recommender/MatrixFactorizationTrainer.cs
Original file line numberDiff line numberDiff line change
Expand Up@@ -31,24 +31,19 @@ namespace Microsoft.ML.Trainers
/// and the value at the location specified by the two indexes. For an example data structure of a tuple, one can use:
/// </para>
/// <code language="csharp">
/// // The following variables defines the shape of a m-by-n matrix. The variable firstRowIndex indicates the integer that
/// // would be mapped to the first row index. If user data uses 0-based indices for rows, firstRowIndex can be set to 0.
/// // Similarly, for 1-based indices, firstRowIndex could be 1.
/// const int firstRowIndex = 1;
/// const int firstColumnIndex = 1;
/// // The following variables defines the shape of a m-by-n matrix. Indexes start with 0; that is, our indexing system
/// // is 0-based.
/// const int m = 60;
/// const int n = 100;
///
/// // A tuple of row index, column index, and rating. It specifies a value in the rating matrix.
/// class MatrixElement
/// {
/// // Matrix column index starts from firstColumnIndex and is at most firstColumnIndex+n-1.
/// // Contieuous=true means that all values from firstColumnIndex to firstColumnIndex+n-1 are allowed keys.
/// // [KeyType(Contiguous = true, Count = n, Min = firstColumnIndex)]
/// // public uint MatrixColumnIndex;
/// // Matrix row index starts from firstRowIndex and is at most firstRowIndex+m-1.
/// // Contieuous=true means that all values from firstRowIndex to firstRowIndex+m-1 are allowed keys.
/// [KeyType(Contiguous = true, Count = m, Min = firstRowIndex)]
/// // Matrix column index starts from 0 and is at most n-1.
/// [KeyType(n)]
/// public uint MatrixColumnIndex;
/// // Matrix row index starts from 0 and is at most m-1.
/// [KeyType(m)]
/// public uint MatrixRowIndex;
/// // The rating at the MatrixColumnIndex-th column and the MatrixRowIndex-th row.
/// public float Value;
Expand All@@ -65,7 +60,7 @@ namespace Microsoft.ML.Trainers
/// <i>R</i> is approximated by the product of <i>P</i>'s transpose and <i>Q</i>. This trainer implements
/// <a href='https://www.csie.ntu.edu.tw/~cjlin/papers/libmf/mf_adaptive_pakdd.pdf'>a stochastic gradient method</a> for finding <i>P</i>
/// and <i>Q</i> via minimizing the distance between<i> R</i> and the product of <i>P</i>'s transpose and Q.</para>.
/// <para>For users interested in the mathematical details, please see the references below.</para>
/// <para>The underlying library used in ML.NET matrix factorization can be found on <a href='https://github.com/cjlin1/libmf'>a Github repository</a>. For users interested in the mathematical details, please see the references below.</para>
/// <list type = 'bullet'>
/// <item>
/// <description><a href='https://www.csie.ntu.edu.tw/~cjlin/papers/libmf/libmf_journal.pdf' > A Fast Parallel Stochastic Gradient Method for Matrix Factorization in Shared Memory Systems</a></description>
Expand All@@ -76,6 +71,9 @@ namespace Microsoft.ML.Trainers
/// <item>
/// <description><a href='https://www.csie.ntu.edu.tw/~cjlin/papers/libmf/libmf_open_source.pdf' > LIBMF: A Library for Parallel Matrix Factorization in Shared-memory Systems</a></description>
/// </item>
/// <item>
/// <description><a href='https://www.csie.ntu.edu.tw/~cjlin/papers/one-class-mf/biased-mf-sdm-with-supp.pdf' > Selection of Negative Samples for One-class Matrix Factorization</a></description>
/// </item>
/// </list>
/// </remarks>
/// <example>
Expand Down
84 changes: 45 additions & 39 deletions src/Microsoft.ML.Recommender/SafeTrainingAndModelBuffer.cs
Original file line numberDiff line numberDiff line change
Expand Up@@ -17,31 +17,50 @@ namespace Microsoft.ML.Recommender.Internal
/// </summary>
internal sealed class SafeTrainingAndModelBuffer : IDisposable
{
[StructLayout(LayoutKind.Explicit)]
[StructLayout(LayoutKind.Sequential)]
private struct MFNode
{
[FieldOffset(0)]
/// <summary>
/// Row index.
/// </summary>
public int U;
[FieldOffset(4)]

/// <summary>
/// Column index;
/// </summary>
public int V;
[FieldOffset(8)]

/// <summary>
/// Matrix element's value at <see cref="U"/>-th row and <see cref="V"/>-th column.
/// </summary>
public float R;
}

[StructLayout(LayoutKind.Explicit)]
[StructLayout(LayoutKind.Sequential)]
private unsafe struct MFProblem
{
[FieldOffset(0)]
/// <summary>
/// Number of rows.
/// </summary>
public int M;
[FieldOffset(4)]

/// <summary>
/// Number of columns.
/// </summary>
public int N;
[FieldOffset(8)]

/// <summary>
/// Number of specified matrix elements in <see cref="R"/>.
/// </summary>
public long Nnz;
[FieldOffset(16)]

/// <summary>
/// Specified matrix elements.
/// </summary>
public MFNode* R;
}

[StructLayout(LayoutKind.Explicit)]
[StructLayout(LayoutKind.Sequential)]
private struct MFParameter
{
/// <summary>
Expand All@@ -58,130 +77,117 @@ private struct MFParameter
/// Fun 12 is solved by a coordinate descent method while other functions invoke
/// a stochastic gradient method.
/// </summary>
[FieldOffset(0)]
public int Fun;

/// <summary>
/// Rank of factor matrices.
/// </summary>
[FieldOffset(4)]
public int K;

/// <summary>
/// Number of threads which can be used for training.
/// </summary>
[FieldOffset(8)]
public int NrThreads;

/// <summary>
/// Number of blocks that the training matrix is divided into. The parallel stochastic gradient
/// method in LIBMF processes assigns each thread a block at one time. The ratings in one block
/// would be sequentially accessed (not randomaly accessed like standard stochastic gradient methods).
/// </summary>
[FieldOffset(12)]
public int NrBins;

/// <summary>
/// Number of training iteration. At one iteration, all values in the training matrix are roughly accessed once.
/// </summary>
[FieldOffset(16)]
public int NrIters;

/// <summary>
/// L1-norm regularization coefficient of left factor matrix.
/// </summary>
[FieldOffset(20)]
public float LambdaP1;

/// <summary>
/// L2-norm regularization coefficient of left factor matrix.
/// </summary>
[FieldOffset(24)]
public float LambdaP2;

/// <summary>
/// L1-norm regularization coefficient of right factor matrix.
/// </summary>
[FieldOffset(28)]
public float LambdaQ1;

/// <summary>
/// L2-norm regularization coefficient of right factor matrix.
/// </summary>
[FieldOffset(32)]
public float LambdaQ2;

/// <summary>
/// Learning rate of LIBMF's stochastic gradient method.
/// </summary>
[FieldOffset(36)]
public float Eta;

/// <summary>
/// Coefficient of loss function on unobserved entries in the training matrix. It's used only with fun=12.
/// </summary>
[FieldOffset(40)]
public float Alpha;

/// <summary>
/// Desired value of unobserved entries in the training matrix. It's used only with fun=12.
/// </summary>
[FieldOffset(44)]
public float C;

/// <summary>
/// Specify if the factor matrices should be non-negative.
/// </summary>
[FieldOffset(48)]
public int DoNmf;
public byte DoNmf;

/// <summary>
/// Set to true so that LIBMF may produce less information to STDOUT.
/// </summary>
[FieldOffset(52)]
public int Quiet;
public byte Quiet;

/// <summary>
/// Set to false so that LIBMF may reuse and modifiy the data passed in.
/// </summary>
[FieldOffset(56)]
public int CopyData;
public byte CopyData;
}

[StructLayout(LayoutKind.Explicit)]
[StructLayout(LayoutKind.Sequential)]
private unsafe struct MFModel
{
[FieldOffset(0)]
/// <summary>
/// See <see cref="MFParameter.Fun"/>.
/// </summary>
public int Fun;

/// <summary>
/// Number of rows in the training matrix.
/// </summary>
[FieldOffset(4)]
public int M;

/// <summary>
/// Number of columns in the training matrix.
/// </summary>
[FieldOffset(8)]
public int N;

/// <summary>
/// Rank of factor matrices.
/// </summary>
[FieldOffset(12)]
public int K;

/// <summary>
/// Average value in the training matrix.
/// </summary>
[FieldOffset(16)]
public float B;

/// <summary>
/// Left factor matrix. Its shape is M-by-K stored in row-major format.
/// </summary>
[FieldOffset(24)] // pointer is 8-byte on 64-bit machine.
public float* P;

/// <summary>
/// Right factor matrix. Its shape is N-by-K stored in row-major format.
/// </summary>
[FieldOffset(32)] // pointer is 8-byte on 64-bit machine.
public float* Q;
}

Expand DownExpand Up@@ -223,9 +229,9 @@ public SafeTrainingAndModelBuffer(IHostEnvironment env, int fun, int k, int nrTh
_mfParam.Eta = (float)eta;
_mfParam.Alpha = (float)alpha;
_mfParam.C = (float)c;
_mfParam.DoNmf = doNmf ? 1 : 0;
_mfParam.Quiet = quiet ? 1 : 0;
_mfParam.CopyData = copyData ? 1 : 0;
_mfParam.DoNmf = doNmf ? (byte)1 : (byte)0;
_mfParam.Quiet = quiet ? (byte)1 : (byte)0;
_mfParam.CopyData = copyData ? (byte)1 : (byte)0;
}

~SafeTrainingAndModelBuffer()
Expand Down
21 changes: 17 additions & 4 deletions src/Native/MatrixFactorizationNative/CMakeLists.txt
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,25 @@
project (MatrixFactorizationNative)
add_definitions(-D_SCL_SECURE_NO_WARNINGS)
add_definitions(-DUSEOMP)
add_definitions(-DUSESSE)

include_directories(libmf)

set(SOURCES
UnmanagedMemory.cpp
libmf/mf.cpp
)
if(UNIX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -O3 -pthread -std=c++0x -march=native")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fopenmp")
if (APPLE)
include_directories("/usr/local/opt/libomp/include")
link_directories("/usr/local/opt/libomp/lib")
endif()
endif()

if(WIN32)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4 /nologo /O2 /EHsc /D \"_CRT_SECURE_NO_DEPRECATE\" /openmp")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}")
endif()

set(SOURCES UnmanagedMemory.cpp libmf/mf.cpp)

if(NOT WIN32)
list(APPEND SOURCES ${VERSION_FILE_PATH})
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 11 additions & 13 deletions src/Microsoft.ML.Recommender/MatrixFactorizationTrainer.cs
Original file line numberDiff line numberDiff line change
Expand Up@@ -31,24 +31,19 @@ namespace Microsoft.ML.Trainers
/// and the value at the location specified by the two indexes. For an example data structure of a tuple, one can use:
/// </para>
/// <code language="csharp">
/// // The following variables defines the shape of a m-by-n matrix. The variable firstRowIndex indicates the integer that
/// // would be mapped to the first row index. If user data uses 0-based indices for rows, firstRowIndex can be set to 0.
/// // Similarly, for 1-based indices, firstRowIndex could be 1.
/// const int firstRowIndex = 1;
/// const int firstColumnIndex = 1;
/// // The following variables defines the shape of a m-by-n matrix. Indexes start with 0; that is, our indexing system
/// // is 0-based.
/// const int m = 60;
/// const int n = 100;
///
/// // A tuple of row index, column index, and rating. It specifies a value in the rating matrix.
/// class MatrixElement
/// {
/// // Matrix column index starts from firstColumnIndex and is at most firstColumnIndex+n-1.
/// // Contieuous=true means that all values from firstColumnIndex to firstColumnIndex+n-1 are allowed keys.
/// // [KeyType(Contiguous = true, Count = n, Min = firstColumnIndex)]
/// // public uint MatrixColumnIndex;
/// // Matrix row index starts from firstRowIndex and is at most firstRowIndex+m-1.
/// // Contieuous=true means that all values from firstRowIndex to firstRowIndex+m-1 are allowed keys.
/// [KeyType(Contiguous = true, Count = m, Min = firstRowIndex)]
/// // Matrix column index starts from 0 and is at most n-1.
/// [KeyType(n)]
/// public uint MatrixColumnIndex;
/// // Matrix row index starts from 0 and is at most m-1.
/// [KeyType(m)]
/// public uint MatrixRowIndex;
/// // The rating at the MatrixColumnIndex-th column and the MatrixRowIndex-th row.
/// public float Value;
Expand All@@ -65,7 +60,7 @@ namespace Microsoft.ML.Trainers
/// <i>R</i> is approximated by the product of <i>P</i>'s transpose and <i>Q</i>. This trainer implements
/// <a href='https://www.csie.ntu.edu.tw/~cjlin/papers/libmf/mf_adaptive_pakdd.pdf'>a stochastic gradient method</a> for finding <i>P</i>
/// and <i>Q</i> via minimizing the distance between<i> R</i> and the product of <i>P</i>'s transpose and Q.</para>.
/// <para>For users interested in the mathematical details, please see the references below.</para>
/// <para>The underlying library used in ML.NET matrix factorization can be found on <a href='https://github.com/cjlin1/libmf'>a Github repository</a>. For users interested in the mathematical details, please see the references below.</para>
/// <list type = 'bullet'>
/// <item>
/// <description><a href='https://www.csie.ntu.edu.tw/~cjlin/papers/libmf/libmf_journal.pdf' > A Fast Parallel Stochastic Gradient Method for Matrix Factorization in Shared Memory Systems</a></description>
Expand All@@ -76,6 +71,9 @@ namespace Microsoft.ML.Trainers
/// <item>
/// <description><a href='https://www.csie.ntu.edu.tw/~cjlin/papers/libmf/libmf_open_source.pdf' > LIBMF: A Library for Parallel Matrix Factorization in Shared-memory Systems</a></description>
/// </item>
/// <item>
/// <description><a href='https://www.csie.ntu.edu.tw/~cjlin/papers/one-class-mf/biased-mf-sdm-with-supp.pdf' > Selection of Negative Samples for One-class Matrix Factorization</a></description>
/// </item>
/// </list>
/// </remarks>
/// <example>
Expand Down
84 changes: 45 additions & 39 deletions src/Microsoft.ML.Recommender/SafeTrainingAndModelBuffer.cs
Original file line numberDiff line numberDiff line change
Expand Up@@ -17,31 +17,50 @@ namespace Microsoft.ML.Recommender.Internal
/// </summary>
internal sealed class SafeTrainingAndModelBuffer : IDisposable
{
[StructLayout(LayoutKind.Explicit)]
[StructLayout(LayoutKind.Sequential)]
private struct MFNode
{
[FieldOffset(0)]
/// <summary>
/// Row index.
/// </summary>
public int U;
[FieldOffset(4)]

/// <summary>
/// Column index;
/// </summary>
public int V;
[FieldOffset(8)]

/// <summary>
/// Matrix element's value at <see cref="U"/>-th row and <see cref="V"/>-th column.
/// </summary>
public float R;
}

[StructLayout(LayoutKind.Explicit)]
[StructLayout(LayoutKind.Sequential)]
private unsafe struct MFProblem
{
[FieldOffset(0)]
/// <summary>
/// Number of rows.
/// </summary>
public int M;
[FieldOffset(4)]

/// <summary>
/// Number of columns.
/// </summary>
public int N;
[FieldOffset(8)]

/// <summary>
/// Number of specified matrix elements in <see cref="R"/>.
/// </summary>
public long Nnz;
[FieldOffset(16)]

/// <summary>
/// Specified matrix elements.
/// </summary>
public MFNode* R;
}

[StructLayout(LayoutKind.Explicit)]
[StructLayout(LayoutKind.Sequential)]
private struct MFParameter
{
/// <summary>
Expand All@@ -58,130 +77,117 @@ private struct MFParameter
/// Fun 12 is solved by a coordinate descent method while other functions invoke
/// a stochastic gradient method.
/// </summary>
[FieldOffset(0)]
public int Fun;

/// <summary>
/// Rank of factor matrices.
/// </summary>
[FieldOffset(4)]
public int K;

/// <summary>
/// Number of threads which can be used for training.
/// </summary>
[FieldOffset(8)]
public int NrThreads;

/// <summary>
/// Number of blocks that the training matrix is divided into. The parallel stochastic gradient
/// method in LIBMF processes assigns each thread a block at one time. The ratings in one block
/// would be sequentially accessed (not randomaly accessed like standard stochastic gradient methods).
/// </summary>
[FieldOffset(12)]
public int NrBins;

/// <summary>
/// Number of training iteration. At one iteration, all values in the training matrix are roughly accessed once.
/// </summary>
[FieldOffset(16)]
public int NrIters;

/// <summary>
/// L1-norm regularization coefficient of left factor matrix.
/// </summary>
[FieldOffset(20)]
public float LambdaP1;

/// <summary>
/// L2-norm regularization coefficient of left factor matrix.
/// </summary>
[FieldOffset(24)]
public float LambdaP2;

/// <summary>
/// L1-norm regularization coefficient of right factor matrix.
/// </summary>
[FieldOffset(28)]
public float LambdaQ1;

/// <summary>
/// L2-norm regularization coefficient of right factor matrix.
/// </summary>
[FieldOffset(32)]
public float LambdaQ2;

/// <summary>
/// Learning rate of LIBMF's stochastic gradient method.
/// </summary>
[FieldOffset(36)]
public float Eta;

/// <summary>
/// Coefficient of loss function on unobserved entries in the training matrix. It's used only with fun=12.
/// </summary>
[FieldOffset(40)]
public float Alpha;

/// <summary>
/// Desired value of unobserved entries in the training matrix. It's used only with fun=12.
/// </summary>
[FieldOffset(44)]
public float C;

/// <summary>
/// Specify if the factor matrices should be non-negative.
/// </summary>
[FieldOffset(48)]
public int DoNmf;
public byte DoNmf;

/// <summary>
/// Set to true so that LIBMF may produce less information to STDOUT.
/// </summary>
[FieldOffset(52)]
public int Quiet;
public byte Quiet;

/// <summary>
/// Set to false so that LIBMF may reuse and modifiy the data passed in.
/// </summary>
[FieldOffset(56)]
public int CopyData;
public byte CopyData;
}

[StructLayout(LayoutKind.Explicit)]
[StructLayout(LayoutKind.Sequential)]
private unsafe struct MFModel
{
[FieldOffset(0)]
/// <summary>
/// See <see cref="MFParameter.Fun"/>.
/// </summary>
public int Fun;

/// <summary>
/// Number of rows in the training matrix.
/// </summary>
[FieldOffset(4)]
public int M;

/// <summary>
/// Number of columns in the training matrix.
/// </summary>
[FieldOffset(8)]
public int N;

/// <summary>
/// Rank of factor matrices.
/// </summary>
[FieldOffset(12)]
public int K;

/// <summary>
/// Average value in the training matrix.
/// </summary>
[FieldOffset(16)]
public float B;

/// <summary>
/// Left factor matrix. Its shape is M-by-K stored in row-major format.
/// </summary>
[FieldOffset(24)] // pointer is 8-byte on 64-bit machine.
public float* P;

/// <summary>
/// Right factor matrix. Its shape is N-by-K stored in row-major format.
/// </summary>
[FieldOffset(32)] // pointer is 8-byte on 64-bit machine.
public float* Q;
}

Expand DownExpand Up@@ -223,9 +229,9 @@ public SafeTrainingAndModelBuffer(IHostEnvironment env, int fun, int k, int nrTh
_mfParam.Eta = (float)eta;
_mfParam.Alpha = (float)alpha;
_mfParam.C = (float)c;
_mfParam.DoNmf = doNmf ? 1 : 0;
_mfParam.Quiet = quiet ? 1 : 0;
_mfParam.CopyData = copyData ? 1 : 0;
_mfParam.DoNmf = doNmf ? (byte)1 : (byte)0;
_mfParam.Quiet = quiet ? (byte)1 : (byte)0;
_mfParam.CopyData = copyData ? (byte)1 : (byte)0;
}

~SafeTrainingAndModelBuffer()
Expand Down
21 changes: 17 additions & 4 deletions src/Native/MatrixFactorizationNative/CMakeLists.txt
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,25 @@
project (MatrixFactorizationNative)
add_definitions(-D_SCL_SECURE_NO_WARNINGS)
add_definitions(-DUSEOMP)
add_definitions(-DUSESSE)

include_directories(libmf)

set(SOURCES
UnmanagedMemory.cpp
libmf/mf.cpp
)
if(UNIX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -O3 -pthread -std=c++0x -march=native")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fopenmp")
if (APPLE)
include_directories("/usr/local/opt/libomp/include")
link_directories("/usr/local/opt/libomp/lib")
endif()
endif()

if(WIN32)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4 /nologo /O2 /EHsc /D \"_CRT_SECURE_NO_DEPRECATE\" /openmp")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}")
endif()

set(SOURCES UnmanagedMemory.cpp libmf/mf.cpp)

if(NOT WIN32)
list(APPEND SOURCES ${VERSION_FILE_PATH})
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 11 additions & 13 deletions src/Microsoft.ML.Recommender/MatrixFactorizationTrainer.cs
Original file line numberDiff line numberDiff line change
Expand Up@@ -31,24 +31,19 @@ namespace Microsoft.ML.Trainers
/// and the value at the location specified by the two indexes. For an example data structure of a tuple, one can use:
/// </para>
/// <code language="csharp">
/// // The following variables defines the shape of a m-by-n matrix. The variable firstRowIndex indicates the integer that
/// // would be mapped to the first row index. If user data uses 0-based indices for rows, firstRowIndex can be set to 0.
/// // Similarly, for 1-based indices, firstRowIndex could be 1.
/// const int firstRowIndex = 1;
/// const int firstColumnIndex = 1;
/// // The following variables defines the shape of a m-by-n matrix. Indexes start with 0; that is, our indexing system
/// // is 0-based.
/// const int m = 60;
/// const int n = 100;
///
/// // A tuple of row index, column index, and rating. It specifies a value in the rating matrix.
/// class MatrixElement
/// {
/// // Matrix column index starts from firstColumnIndex and is at most firstColumnIndex+n-1.
/// // Contieuous=true means that all values from firstColumnIndex to firstColumnIndex+n-1 are allowed keys.
/// // [KeyType(Contiguous = true, Count = n, Min = firstColumnIndex)]
/// // public uint MatrixColumnIndex;
/// // Matrix row index starts from firstRowIndex and is at most firstRowIndex+m-1.
/// // Contieuous=true means that all values from firstRowIndex to firstRowIndex+m-1 are allowed keys.
/// [KeyType(Contiguous = true, Count = m, Min = firstRowIndex)]
/// // Matrix column index starts from 0 and is at most n-1.
/// [KeyType(n)]
/// public uint MatrixColumnIndex;
/// // Matrix row index starts from 0 and is at most m-1.
/// [KeyType(m)]
/// public uint MatrixRowIndex;
/// // The rating at the MatrixColumnIndex-th column and the MatrixRowIndex-th row.
/// public float Value;
Expand All@@ -65,7 +60,7 @@ namespace Microsoft.ML.Trainers
/// <i>R</i> is approximated by the product of <i>P</i>'s transpose and <i>Q</i>. This trainer implements
/// <a href='https://www.csie.ntu.edu.tw/~cjlin/papers/libmf/mf_adaptive_pakdd.pdf'>a stochastic gradient method</a> for finding <i>P</i>
/// and <i>Q</i> via minimizing the distance between<i> R</i> and the product of <i>P</i>'s transpose and Q.</para>.
/// <para>For users interested in the mathematical details, please see the references below.</para>
/// <para>The underlying library used in ML.NET matrix factorization can be found on <a href='https://github.com/cjlin1/libmf'>a Github repository</a>. For users interested in the mathematical details, please see the references below.</para>
/// <list type = 'bullet'>
/// <item>
/// <description><a href='https://www.csie.ntu.edu.tw/~cjlin/papers/libmf/libmf_journal.pdf' > A Fast Parallel Stochastic Gradient Method for Matrix Factorization in Shared Memory Systems</a></description>
Expand All@@ -76,6 +71,9 @@ namespace Microsoft.ML.Trainers
/// <item>
/// <description><a href='https://www.csie.ntu.edu.tw/~cjlin/papers/libmf/libmf_open_source.pdf' > LIBMF: A Library for Parallel Matrix Factorization in Shared-memory Systems</a></description>
/// </item>
/// <item>
/// <description><a href='https://www.csie.ntu.edu.tw/~cjlin/papers/one-class-mf/biased-mf-sdm-with-supp.pdf' > Selection of Negative Samples for One-class Matrix Factorization</a></description>
/// </item>
/// </list>
/// </remarks>
/// <example>
Expand Down
84 changes: 45 additions & 39 deletions src/Microsoft.ML.Recommender/SafeTrainingAndModelBuffer.cs
Original file line numberDiff line numberDiff line change
Expand Up@@ -17,31 +17,50 @@ namespace Microsoft.ML.Recommender.Internal
/// </summary>
internal sealed class SafeTrainingAndModelBuffer : IDisposable
{
[StructLayout(LayoutKind.Explicit)]
[StructLayout(LayoutKind.Sequential)]
private struct MFNode
{
[FieldOffset(0)]
/// <summary>
/// Row index.
/// </summary>
public int U;
[FieldOffset(4)]

/// <summary>
/// Column index;
/// </summary>
public int V;
[FieldOffset(8)]

/// <summary>
/// Matrix element's value at <see cref="U"/>-th row and <see cref="V"/>-th column.
/// </summary>
public float R;
}

[StructLayout(LayoutKind.Explicit)]
[StructLayout(LayoutKind.Sequential)]
private unsafe struct MFProblem
{
[FieldOffset(0)]
/// <summary>
/// Number of rows.
/// </summary>
public int M;
[FieldOffset(4)]

/// <summary>
/// Number of columns.
/// </summary>
public int N;
[FieldOffset(8)]

/// <summary>
/// Number of specified matrix elements in <see cref="R"/>.
/// </summary>
public long Nnz;
[FieldOffset(16)]

/// <summary>
/// Specified matrix elements.
/// </summary>
public MFNode* R;
}

[StructLayout(LayoutKind.Explicit)]
[StructLayout(LayoutKind.Sequential)]
private struct MFParameter
{
/// <summary>
Expand All@@ -58,130 +77,117 @@ private struct MFParameter
/// Fun 12 is solved by a coordinate descent method while other functions invoke
/// a stochastic gradient method.
/// </summary>
[FieldOffset(0)]
public int Fun;

/// <summary>
/// Rank of factor matrices.
/// </summary>
[FieldOffset(4)]
public int K;

/// <summary>
/// Number of threads which can be used for training.
/// </summary>
[FieldOffset(8)]
public int NrThreads;

/// <summary>
/// Number of blocks that the training matrix is divided into. The parallel stochastic gradient
/// method in LIBMF processes assigns each thread a block at one time. The ratings in one block
/// would be sequentially accessed (not randomaly accessed like standard stochastic gradient methods).
/// </summary>
[FieldOffset(12)]
public int NrBins;

/// <summary>
/// Number of training iteration. At one iteration, all values in the training matrix are roughly accessed once.
/// </summary>
[FieldOffset(16)]
public int NrIters;

/// <summary>
/// L1-norm regularization coefficient of left factor matrix.
/// </summary>
[FieldOffset(20)]
public float LambdaP1;

/// <summary>
/// L2-norm regularization coefficient of left factor matrix.
/// </summary>
[FieldOffset(24)]
public float LambdaP2;

/// <summary>
/// L1-norm regularization coefficient of right factor matrix.
/// </summary>
[FieldOffset(28)]
public float LambdaQ1;

/// <summary>
/// L2-norm regularization coefficient of right factor matrix.
/// </summary>
[FieldOffset(32)]
public float LambdaQ2;

/// <summary>
/// Learning rate of LIBMF's stochastic gradient method.
/// </summary>
[FieldOffset(36)]
public float Eta;

/// <summary>
/// Coefficient of loss function on unobserved entries in the training matrix. It's used only with fun=12.
/// </summary>
[FieldOffset(40)]
public float Alpha;

/// <summary>
/// Desired value of unobserved entries in the training matrix. It's used only with fun=12.
/// </summary>
[FieldOffset(44)]
public float C;

/// <summary>
/// Specify if the factor matrices should be non-negative.
/// </summary>
[FieldOffset(48)]
public int DoNmf;
public byte DoNmf;

/// <summary>
/// Set to true so that LIBMF may produce less information to STDOUT.
/// </summary>
[FieldOffset(52)]
public int Quiet;
public byte Quiet;

/// <summary>
/// Set to false so that LIBMF may reuse and modifiy the data passed in.
/// </summary>
[FieldOffset(56)]
public int CopyData;
public byte CopyData;
}

[StructLayout(LayoutKind.Explicit)]
[StructLayout(LayoutKind.Sequential)]
private unsafe struct MFModel
{
[FieldOffset(0)]
/// <summary>
/// See <see cref="MFParameter.Fun"/>.
/// </summary>
public int Fun;

/// <summary>
/// Number of rows in the training matrix.
/// </summary>
[FieldOffset(4)]
public int M;

/// <summary>
/// Number of columns in the training matrix.
/// </summary>
[FieldOffset(8)]
public int N;

/// <summary>
/// Rank of factor matrices.
/// </summary>
[FieldOffset(12)]
public int K;

/// <summary>
/// Average value in the training matrix.
/// </summary>
[FieldOffset(16)]
public float B;

/// <summary>
/// Left factor matrix. Its shape is M-by-K stored in row-major format.
/// </summary>
[FieldOffset(24)] // pointer is 8-byte on 64-bit machine.
public float* P;

/// <summary>
/// Right factor matrix. Its shape is N-by-K stored in row-major format.
/// </summary>
[FieldOffset(32)] // pointer is 8-byte on 64-bit machine.
public float* Q;
}

Expand DownExpand Up@@ -223,9 +229,9 @@ public SafeTrainingAndModelBuffer(IHostEnvironment env, int fun, int k, int nrTh
_mfParam.Eta = (float)eta;
_mfParam.Alpha = (float)alpha;
_mfParam.C = (float)c;
_mfParam.DoNmf = doNmf ? 1 : 0;
_mfParam.Quiet = quiet ? 1 : 0;
_mfParam.CopyData = copyData ? 1 : 0;
_mfParam.DoNmf = doNmf ? (byte)1 : (byte)0;
_mfParam.Quiet = quiet ? (byte)1 : (byte)0;
_mfParam.CopyData = copyData ? (byte)1 : (byte)0;
}

~SafeTrainingAndModelBuffer()
Expand Down
21 changes: 17 additions & 4 deletions src/Native/MatrixFactorizationNative/CMakeLists.txt
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,25 @@
project (MatrixFactorizationNative)
add_definitions(-D_SCL_SECURE_NO_WARNINGS)
add_definitions(-DUSEOMP)
add_definitions(-DUSESSE)

include_directories(libmf)

set(SOURCES
UnmanagedMemory.cpp
libmf/mf.cpp
)
if(UNIX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -O3 -pthread -std=c++0x -march=native")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fopenmp")
if (APPLE)
include_directories("/usr/local/opt/libomp/include")
link_directories("/usr/local/opt/libomp/lib")
endif()
endif()

if(WIN32)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4 /nologo /O2 /EHsc /D \"_CRT_SECURE_NO_DEPRECATE\" /openmp")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}")
endif()

set(SOURCES UnmanagedMemory.cpp libmf/mf.cpp)

if(NOT WIN32)
list(APPEND SOURCES ${VERSION_FILE_PATH})
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 11 additions & 13 deletions src/Microsoft.ML.Recommender/MatrixFactorizationTrainer.cs
Original file line numberDiff line numberDiff line change
Expand Up@@ -31,24 +31,19 @@ namespace Microsoft.ML.Trainers
/// and the value at the location specified by the two indexes. For an example data structure of a tuple, one can use:
/// </para>
/// <code language="csharp">
/// // The following variables defines the shape of a m-by-n matrix. The variable firstRowIndex indicates the integer that
/// // would be mapped to the first row index. If user data uses 0-based indices for rows, firstRowIndex can be set to 0.
/// // Similarly, for 1-based indices, firstRowIndex could be 1.
/// const int firstRowIndex = 1;
/// const int firstColumnIndex = 1;
/// // The following variables defines the shape of a m-by-n matrix. Indexes start with 0; that is, our indexing system
/// // is 0-based.
/// const int m = 60;
/// const int n = 100;
///
/// // A tuple of row index, column index, and rating. It specifies a value in the rating matrix.
/// class MatrixElement
/// {
/// // Matrix column index starts from firstColumnIndex and is at most firstColumnIndex+n-1.
/// // Contieuous=true means that all values from firstColumnIndex to firstColumnIndex+n-1 are allowed keys.
/// // [KeyType(Contiguous = true, Count = n, Min = firstColumnIndex)]
/// // public uint MatrixColumnIndex;
/// // Matrix row index starts from firstRowIndex and is at most firstRowIndex+m-1.
/// // Contieuous=true means that all values from firstRowIndex to firstRowIndex+m-1 are allowed keys.
/// [KeyType(Contiguous = true, Count = m, Min = firstRowIndex)]
/// // Matrix column index starts from 0 and is at most n-1.
/// [KeyType(n)]
/// public uint MatrixColumnIndex;
/// // Matrix row index starts from 0 and is at most m-1.
/// [KeyType(m)]
/// public uint MatrixRowIndex;
/// // The rating at the MatrixColumnIndex-th column and the MatrixRowIndex-th row.
/// public float Value;
Expand All@@ -65,7 +60,7 @@ namespace Microsoft.ML.Trainers
/// <i>R</i> is approximated by the product of <i>P</i>'s transpose and <i>Q</i>. This trainer implements
/// <a href='https://www.csie.ntu.edu.tw/~cjlin/papers/libmf/mf_adaptive_pakdd.pdf'>a stochastic gradient method</a> for finding <i>P</i>
/// and <i>Q</i> via minimizing the distance between<i> R</i> and the product of <i>P</i>'s transpose and Q.</para>.
/// <para>For users interested in the mathematical details, please see the references below.</para>
/// <para>The underlying library used in ML.NET matrix factorization can be found on <a href='https://github.com/cjlin1/libmf'>a Github repository</a>. For users interested in the mathematical details, please see the references below.</para>
/// <list type = 'bullet'>
/// <item>
/// <description><a href='https://www.csie.ntu.edu.tw/~cjlin/papers/libmf/libmf_journal.pdf' > A Fast Parallel Stochastic Gradient Method for Matrix Factorization in Shared Memory Systems</a></description>
Expand All@@ -76,6 +71,9 @@ namespace Microsoft.ML.Trainers
/// <item>
/// <description><a href='https://www.csie.ntu.edu.tw/~cjlin/papers/libmf/libmf_open_source.pdf' > LIBMF: A Library for Parallel Matrix Factorization in Shared-memory Systems</a></description>
/// </item>
/// <item>
/// <description><a href='https://www.csie.ntu.edu.tw/~cjlin/papers/one-class-mf/biased-mf-sdm-with-supp.pdf' > Selection of Negative Samples for One-class Matrix Factorization</a></description>
/// </item>
/// </list>
/// </remarks>
/// <example>
Expand Down
84 changes: 45 additions & 39 deletions src/Microsoft.ML.Recommender/SafeTrainingAndModelBuffer.cs
Original file line numberDiff line numberDiff line change
Expand Up@@ -17,31 +17,50 @@ namespace Microsoft.ML.Recommender.Internal
/// </summary>
internal sealed class SafeTrainingAndModelBuffer : IDisposable
{
[StructLayout(LayoutKind.Explicit)]
[StructLayout(LayoutKind.Sequential)]
private struct MFNode
{
[FieldOffset(0)]
/// <summary>
/// Row index.
/// </summary>
public int U;
[FieldOffset(4)]

/// <summary>
/// Column index;
/// </summary>
public int V;
[FieldOffset(8)]

/// <summary>
/// Matrix element's value at <see cref="U"/>-th row and <see cref="V"/>-th column.
/// </summary>
public float R;
}

[StructLayout(LayoutKind.Explicit)]
[StructLayout(LayoutKind.Sequential)]
private unsafe struct MFProblem
{
[FieldOffset(0)]
/// <summary>
/// Number of rows.
/// </summary>
public int M;
[FieldOffset(4)]

/// <summary>
/// Number of columns.
/// </summary>
public int N;
[FieldOffset(8)]

/// <summary>
/// Number of specified matrix elements in <see cref="R"/>.
/// </summary>
public long Nnz;
[FieldOffset(16)]

/// <summary>
/// Specified matrix elements.
/// </summary>
public MFNode* R;
}

[StructLayout(LayoutKind.Explicit)]
[StructLayout(LayoutKind.Sequential)]
private struct MFParameter
{
/// <summary>
Expand All@@ -58,130 +77,117 @@ private struct MFParameter
/// Fun 12 is solved by a coordinate descent method while other functions invoke
/// a stochastic gradient method.
/// </summary>
[FieldOffset(0)]
public int Fun;

/// <summary>
/// Rank of factor matrices.
/// </summary>
[FieldOffset(4)]
public int K;

/// <summary>
/// Number of threads which can be used for training.
/// </summary>
[FieldOffset(8)]
public int NrThreads;

/// <summary>
/// Number of blocks that the training matrix is divided into. The parallel stochastic gradient
/// method in LIBMF processes assigns each thread a block at one time. The ratings in one block
/// would be sequentially accessed (not randomaly accessed like standard stochastic gradient methods).
/// </summary>
[FieldOffset(12)]
public int NrBins;

/// <summary>
/// Number of training iteration. At one iteration, all values in the training matrix are roughly accessed once.
/// </summary>
[FieldOffset(16)]
public int NrIters;

/// <summary>
/// L1-norm regularization coefficient of left factor matrix.
/// </summary>
[FieldOffset(20)]
public float LambdaP1;

/// <summary>
/// L2-norm regularization coefficient of left factor matrix.
/// </summary>
[FieldOffset(24)]
public float LambdaP2;

/// <summary>
/// L1-norm regularization coefficient of right factor matrix.
/// </summary>
[FieldOffset(28)]
public float LambdaQ1;

/// <summary>
/// L2-norm regularization coefficient of right factor matrix.
/// </summary>
[FieldOffset(32)]
public float LambdaQ2;

/// <summary>
/// Learning rate of LIBMF's stochastic gradient method.
/// </summary>
[FieldOffset(36)]
public float Eta;

/// <summary>
/// Coefficient of loss function on unobserved entries in the training matrix. It's used only with fun=12.
/// </summary>
[FieldOffset(40)]
public float Alpha;

/// <summary>
/// Desired value of unobserved entries in the training matrix. It's used only with fun=12.
/// </summary>
[FieldOffset(44)]
public float C;

/// <summary>
/// Specify if the factor matrices should be non-negative.
/// </summary>
[FieldOffset(48)]
public int DoNmf;
public byte DoNmf;

/// <summary>
/// Set to true so that LIBMF may produce less information to STDOUT.
/// </summary>
[FieldOffset(52)]
public int Quiet;
public byte Quiet;

/// <summary>
/// Set to false so that LIBMF may reuse and modifiy the data passed in.
/// </summary>
[FieldOffset(56)]
public int CopyData;
public byte CopyData;
}

[StructLayout(LayoutKind.Explicit)]
[StructLayout(LayoutKind.Sequential)]
private unsafe struct MFModel
{
[FieldOffset(0)]
/// <summary>
/// See <see cref="MFParameter.Fun"/>.
/// </summary>
public int Fun;

/// <summary>
/// Number of rows in the training matrix.
/// </summary>
[FieldOffset(4)]
public int M;

/// <summary>
/// Number of columns in the training matrix.
/// </summary>
[FieldOffset(8)]
public int N;

/// <summary>
/// Rank of factor matrices.
/// </summary>
[FieldOffset(12)]
public int K;

/// <summary>
/// Average value in the training matrix.
/// </summary>
[FieldOffset(16)]
public float B;

/// <summary>
/// Left factor matrix. Its shape is M-by-K stored in row-major format.
/// </summary>
[FieldOffset(24)] // pointer is 8-byte on 64-bit machine.
public float* P;

/// <summary>
/// Right factor matrix. Its shape is N-by-K stored in row-major format.
/// </summary>
[FieldOffset(32)] // pointer is 8-byte on 64-bit machine.
public float* Q;
}

Expand DownExpand Up@@ -223,9 +229,9 @@ public SafeTrainingAndModelBuffer(IHostEnvironment env, int fun, int k, int nrTh
_mfParam.Eta = (float)eta;
_mfParam.Alpha = (float)alpha;
_mfParam.C = (float)c;
_mfParam.DoNmf = doNmf ? 1 : 0;
_mfParam.Quiet = quiet ? 1 : 0;
_mfParam.CopyData = copyData ? 1 : 0;
_mfParam.DoNmf = doNmf ? (byte)1 : (byte)0;
_mfParam.Quiet = quiet ? (byte)1 : (byte)0;
_mfParam.CopyData = copyData ? (byte)1 : (byte)0;
}

~SafeTrainingAndModelBuffer()
Expand Down
21 changes: 17 additions & 4 deletions src/Native/MatrixFactorizationNative/CMakeLists.txt
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,25 @@
project (MatrixFactorizationNative)
add_definitions(-D_SCL_SECURE_NO_WARNINGS)
add_definitions(-DUSEOMP)
add_definitions(-DUSESSE)

include_directories(libmf)

set(SOURCES
UnmanagedMemory.cpp
libmf/mf.cpp
)
if(UNIX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -O3 -pthread -std=c++0x -march=native")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fopenmp")
if (APPLE)
include_directories("/usr/local/opt/libomp/include")
link_directories("/usr/local/opt/libomp/lib")
endif()
endif()

if(WIN32)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4 /nologo /O2 /EHsc /D \"_CRT_SECURE_NO_DEPRECATE\" /openmp")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}")
endif()

set(SOURCES UnmanagedMemory.cpp libmf/mf.cpp)

if(NOT WIN32)
list(APPEND SOURCES ${VERSION_FILE_PATH})
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 11 additions & 13 deletions src/Microsoft.ML.Recommender/MatrixFactorizationTrainer.cs
Original file line numberDiff line numberDiff line change
Expand Up@@ -31,24 +31,19 @@ namespace Microsoft.ML.Trainers
/// and the value at the location specified by the two indexes. For an example data structure of a tuple, one can use:
/// </para>
/// <code language="csharp">
/// // The following variables defines the shape of a m-by-n matrix. The variable firstRowIndex indicates the integer that
/// // would be mapped to the first row index. If user data uses 0-based indices for rows, firstRowIndex can be set to 0.
/// // Similarly, for 1-based indices, firstRowIndex could be 1.
/// const int firstRowIndex = 1;
/// const int firstColumnIndex = 1;
/// // The following variables defines the shape of a m-by-n matrix. Indexes start with 0; that is, our indexing system
/// // is 0-based.
/// const int m = 60;
/// const int n = 100;
///
/// // A tuple of row index, column index, and rating. It specifies a value in the rating matrix.
/// class MatrixElement
/// {
/// // Matrix column index starts from firstColumnIndex and is at most firstColumnIndex+n-1.
/// // Contieuous=true means that all values from firstColumnIndex to firstColumnIndex+n-1 are allowed keys.
/// // [KeyType(Contiguous = true, Count = n, Min = firstColumnIndex)]
/// // public uint MatrixColumnIndex;
/// // Matrix row index starts from firstRowIndex and is at most firstRowIndex+m-1.
/// // Contieuous=true means that all values from firstRowIndex to firstRowIndex+m-1 are allowed keys.
/// [KeyType(Contiguous = true, Count = m, Min = firstRowIndex)]
/// // Matrix column index starts from 0 and is at most n-1.
/// [KeyType(n)]
/// public uint MatrixColumnIndex;
/// // Matrix row index starts from 0 and is at most m-1.
/// [KeyType(m)]
/// public uint MatrixRowIndex;
/// // The rating at the MatrixColumnIndex-th column and the MatrixRowIndex-th row.
/// public float Value;
Expand All@@ -65,7 +60,7 @@ namespace Microsoft.ML.Trainers
/// <i>R</i> is approximated by the product of <i>P</i>'s transpose and <i>Q</i>. This trainer implements
/// <a href='https://www.csie.ntu.edu.tw/~cjlin/papers/libmf/mf_adaptive_pakdd.pdf'>a stochastic gradient method</a> for finding <i>P</i>
/// and <i>Q</i> via minimizing the distance between<i> R</i> and the product of <i>P</i>'s transpose and Q.</para>.
/// <para>For users interested in the mathematical details, please see the references below.</para>
/// <para>The underlying library used in ML.NET matrix factorization can be found on <a href='https://github.com/cjlin1/libmf'>a Github repository</a>. For users interested in the mathematical details, please see the references below.</para>
/// <list type = 'bullet'>
/// <item>
/// <description><a href='https://www.csie.ntu.edu.tw/~cjlin/papers/libmf/libmf_journal.pdf' > A Fast Parallel Stochastic Gradient Method for Matrix Factorization in Shared Memory Systems</a></description>
Expand All@@ -76,6 +71,9 @@ namespace Microsoft.ML.Trainers
/// <item>
/// <description><a href='https://www.csie.ntu.edu.tw/~cjlin/papers/libmf/libmf_open_source.pdf' > LIBMF: A Library for Parallel Matrix Factorization in Shared-memory Systems</a></description>
/// </item>
/// <item>
/// <description><a href='https://www.csie.ntu.edu.tw/~cjlin/papers/one-class-mf/biased-mf-sdm-with-supp.pdf' > Selection of Negative Samples for One-class Matrix Factorization</a></description>
/// </item>
/// </list>
/// </remarks>
/// <example>
Expand Down
84 changes: 45 additions & 39 deletions src/Microsoft.ML.Recommender/SafeTrainingAndModelBuffer.cs
Original file line numberDiff line numberDiff line change
Expand Up@@ -17,31 +17,50 @@ namespace Microsoft.ML.Recommender.Internal
/// </summary>
internal sealed class SafeTrainingAndModelBuffer : IDisposable
{
[StructLayout(LayoutKind.Explicit)]
[StructLayout(LayoutKind.Sequential)]
private struct MFNode
{
[FieldOffset(0)]
/// <summary>
/// Row index.
/// </summary>
public int U;
[FieldOffset(4)]

/// <summary>
/// Column index;
/// </summary>
public int V;
[FieldOffset(8)]

/// <summary>
/// Matrix element's value at <see cref="U"/>-th row and <see cref="V"/>-th column.
/// </summary>
public float R;
}

[StructLayout(LayoutKind.Explicit)]
[StructLayout(LayoutKind.Sequential)]
private unsafe struct MFProblem
{
[FieldOffset(0)]
/// <summary>
/// Number of rows.
/// </summary>
public int M;
[FieldOffset(4)]

/// <summary>
/// Number of columns.
/// </summary>
public int N;
[FieldOffset(8)]

/// <summary>
/// Number of specified matrix elements in <see cref="R"/>.
/// </summary>
public long Nnz;
[FieldOffset(16)]

/// <summary>
/// Specified matrix elements.
/// </summary>
public MFNode* R;
}

[StructLayout(LayoutKind.Explicit)]
[StructLayout(LayoutKind.Sequential)]
private struct MFParameter
{
/// <summary>
Expand All@@ -58,130 +77,117 @@ private struct MFParameter
/// Fun 12 is solved by a coordinate descent method while other functions invoke
/// a stochastic gradient method.
/// </summary>
[FieldOffset(0)]
public int Fun;

/// <summary>
/// Rank of factor matrices.
/// </summary>
[FieldOffset(4)]
public int K;

/// <summary>
/// Number of threads which can be used for training.
/// </summary>
[FieldOffset(8)]
public int NrThreads;

/// <summary>
/// Number of blocks that the training matrix is divided into. The parallel stochastic gradient
/// method in LIBMF processes assigns each thread a block at one time. The ratings in one block
/// would be sequentially accessed (not randomaly accessed like standard stochastic gradient methods).
/// </summary>
[FieldOffset(12)]
public int NrBins;

/// <summary>
/// Number of training iteration. At one iteration, all values in the training matrix are roughly accessed once.
/// </summary>
[FieldOffset(16)]
public int NrIters;

/// <summary>
/// L1-norm regularization coefficient of left factor matrix.
/// </summary>
[FieldOffset(20)]
public float LambdaP1;

/// <summary>
/// L2-norm regularization coefficient of left factor matrix.
/// </summary>
[FieldOffset(24)]
public float LambdaP2;

/// <summary>
/// L1-norm regularization coefficient of right factor matrix.
/// </summary>
[FieldOffset(28)]
public float LambdaQ1;

/// <summary>
/// L2-norm regularization coefficient of right factor matrix.
/// </summary>
[FieldOffset(32)]
public float LambdaQ2;

/// <summary>
/// Learning rate of LIBMF's stochastic gradient method.
/// </summary>
[FieldOffset(36)]
public float Eta;

/// <summary>
/// Coefficient of loss function on unobserved entries in the training matrix. It's used only with fun=12.
/// </summary>
[FieldOffset(40)]
public float Alpha;

/// <summary>
/// Desired value of unobserved entries in the training matrix. It's used only with fun=12.
/// </summary>
[FieldOffset(44)]
public float C;

/// <summary>
/// Specify if the factor matrices should be non-negative.
/// </summary>
[FieldOffset(48)]
public int DoNmf;
public byte DoNmf;

/// <summary>
/// Set to true so that LIBMF may produce less information to STDOUT.
/// </summary>
[FieldOffset(52)]
public int Quiet;
public byte Quiet;

/// <summary>
/// Set to false so that LIBMF may reuse and modifiy the data passed in.
/// </summary>
[FieldOffset(56)]
public int CopyData;
public byte CopyData;
}

[StructLayout(LayoutKind.Explicit)]
[StructLayout(LayoutKind.Sequential)]
private unsafe struct MFModel
{
[FieldOffset(0)]
/// <summary>
/// See <see cref="MFParameter.Fun"/>.
/// </summary>
public int Fun;

/// <summary>
/// Number of rows in the training matrix.
/// </summary>
[FieldOffset(4)]
public int M;

/// <summary>
/// Number of columns in the training matrix.
/// </summary>
[FieldOffset(8)]
public int N;

/// <summary>
/// Rank of factor matrices.
/// </summary>
[FieldOffset(12)]
public int K;

/// <summary>
/// Average value in the training matrix.
/// </summary>
[FieldOffset(16)]
public float B;

/// <summary>
/// Left factor matrix. Its shape is M-by-K stored in row-major format.
/// </summary>
[FieldOffset(24)] // pointer is 8-byte on 64-bit machine.
public float* P;

/// <summary>
/// Right factor matrix. Its shape is N-by-K stored in row-major format.
/// </summary>
[FieldOffset(32)] // pointer is 8-byte on 64-bit machine.
public float* Q;
}

Expand DownExpand Up@@ -223,9 +229,9 @@ public SafeTrainingAndModelBuffer(IHostEnvironment env, int fun, int k, int nrTh
_mfParam.Eta = (float)eta;
_mfParam.Alpha = (float)alpha;
_mfParam.C = (float)c;
_mfParam.DoNmf = doNmf ? 1 : 0;
_mfParam.Quiet = quiet ? 1 : 0;
_mfParam.CopyData = copyData ? 1 : 0;
_mfParam.DoNmf = doNmf ? (byte)1 : (byte)0;
_mfParam.Quiet = quiet ? (byte)1 : (byte)0;
_mfParam.CopyData = copyData ? (byte)1 : (byte)0;
}

~SafeTrainingAndModelBuffer()
Expand Down
21 changes: 17 additions & 4 deletions src/Native/MatrixFactorizationNative/CMakeLists.txt
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,25 @@
project (MatrixFactorizationNative)
add_definitions(-D_SCL_SECURE_NO_WARNINGS)
add_definitions(-DUSEOMP)
add_definitions(-DUSESSE)

include_directories(libmf)

set(SOURCES
UnmanagedMemory.cpp
libmf/mf.cpp
)
if(UNIX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -O3 -pthread -std=c++0x -march=native")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fopenmp")
if (APPLE)
include_directories("/usr/local/opt/libomp/include")
link_directories("/usr/local/opt/libomp/lib")
endif()
endif()

if(WIN32)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4 /nologo /O2 /EHsc /D \"_CRT_SECURE_NO_DEPRECATE\" /openmp")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}")
endif()

set(SOURCES UnmanagedMemory.cpp libmf/mf.cpp)

if(NOT WIN32)
list(APPEND SOURCES ${VERSION_FILE_PATH})
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 11 additions & 13 deletions src/Microsoft.ML.Recommender/MatrixFactorizationTrainer.cs
Original file line numberDiff line numberDiff line change
Expand Up@@ -31,24 +31,19 @@ namespace Microsoft.ML.Trainers
/// and the value at the location specified by the two indexes. For an example data structure of a tuple, one can use:
/// </para>
/// <code language="csharp">
/// // The following variables defines the shape of a m-by-n matrix. The variable firstRowIndex indicates the integer that
/// // would be mapped to the first row index. If user data uses 0-based indices for rows, firstRowIndex can be set to 0.
/// // Similarly, for 1-based indices, firstRowIndex could be 1.
/// const int firstRowIndex = 1;
/// const int firstColumnIndex = 1;
/// // The following variables defines the shape of a m-by-n matrix. Indexes start with 0; that is, our indexing system
/// // is 0-based.
/// const int m = 60;
/// const int n = 100;
///
/// // A tuple of row index, column index, and rating. It specifies a value in the rating matrix.
/// class MatrixElement
/// {
/// // Matrix column index starts from firstColumnIndex and is at most firstColumnIndex+n-1.
/// // Contieuous=true means that all values from firstColumnIndex to firstColumnIndex+n-1 are allowed keys.
/// // [KeyType(Contiguous = true, Count = n, Min = firstColumnIndex)]
/// // public uint MatrixColumnIndex;
/// // Matrix row index starts from firstRowIndex and is at most firstRowIndex+m-1.
/// // Contieuous=true means that all values from firstRowIndex to firstRowIndex+m-1 are allowed keys.
/// [KeyType(Contiguous = true, Count = m, Min = firstRowIndex)]
/// // Matrix column index starts from 0 and is at most n-1.
/// [KeyType(n)]
/// public uint MatrixColumnIndex;
/// // Matrix row index starts from 0 and is at most m-1.
/// [KeyType(m)]
/// public uint MatrixRowIndex;
/// // The rating at the MatrixColumnIndex-th column and the MatrixRowIndex-th row.
/// public float Value;
Expand All@@ -65,7 +60,7 @@ namespace Microsoft.ML.Trainers
/// <i>R</i> is approximated by the product of <i>P</i>'s transpose and <i>Q</i>. This trainer implements
/// <a href='https://www.csie.ntu.edu.tw/~cjlin/papers/libmf/mf_adaptive_pakdd.pdf'>a stochastic gradient method</a> for finding <i>P</i>
/// and <i>Q</i> via minimizing the distance between<i> R</i> and the product of <i>P</i>'s transpose and Q.</para>.
/// <para>For users interested in the mathematical details, please see the references below.</para>
/// <para>The underlying library used in ML.NET matrix factorization can be found on <a href='https://github.com/cjlin1/libmf'>a Github repository</a>. For users interested in the mathematical details, please see the references below.</para>
/// <list type = 'bullet'>
/// <item>
/// <description><a href='https://www.csie.ntu.edu.tw/~cjlin/papers/libmf/libmf_journal.pdf' > A Fast Parallel Stochastic Gradient Method for Matrix Factorization in Shared Memory Systems</a></description>
Expand All@@ -76,6 +71,9 @@ namespace Microsoft.ML.Trainers
/// <item>
/// <description><a href='https://www.csie.ntu.edu.tw/~cjlin/papers/libmf/libmf_open_source.pdf' > LIBMF: A Library for Parallel Matrix Factorization in Shared-memory Systems</a></description>
/// </item>
/// <item>
/// <description><a href='https://www.csie.ntu.edu.tw/~cjlin/papers/one-class-mf/biased-mf-sdm-with-supp.pdf' > Selection of Negative Samples for One-class Matrix Factorization</a></description>
/// </item>
/// </list>
/// </remarks>
/// <example>
Expand Down
84 changes: 45 additions & 39 deletions src/Microsoft.ML.Recommender/SafeTrainingAndModelBuffer.cs
Original file line numberDiff line numberDiff line change
Expand Up@@ -17,31 +17,50 @@ namespace Microsoft.ML.Recommender.Internal
/// </summary>
internal sealed class SafeTrainingAndModelBuffer : IDisposable
{
[StructLayout(LayoutKind.Explicit)]
[StructLayout(LayoutKind.Sequential)]
private struct MFNode
{
[FieldOffset(0)]
/// <summary>
/// Row index.
/// </summary>
public int U;
[FieldOffset(4)]

/// <summary>
/// Column index;
/// </summary>
public int V;
[FieldOffset(8)]

/// <summary>
/// Matrix element's value at <see cref="U"/>-th row and <see cref="V"/>-th column.
/// </summary>
public float R;
}

[StructLayout(LayoutKind.Explicit)]
[StructLayout(LayoutKind.Sequential)]
private unsafe struct MFProblem
{
[FieldOffset(0)]
/// <summary>
/// Number of rows.
/// </summary>
public int M;
[FieldOffset(4)]

/// <summary>
/// Number of columns.
/// </summary>
public int N;
[FieldOffset(8)]

/// <summary>
/// Number of specified matrix elements in <see cref="R"/>.
/// </summary>
public long Nnz;
[FieldOffset(16)]

/// <summary>
/// Specified matrix elements.
/// </summary>
public MFNode* R;
}

[StructLayout(LayoutKind.Explicit)]
[StructLayout(LayoutKind.Sequential)]
private struct MFParameter
{
/// <summary>
Expand All@@ -58,130 +77,117 @@ private struct MFParameter
/// Fun 12 is solved by a coordinate descent method while other functions invoke
/// a stochastic gradient method.
/// </summary>
[FieldOffset(0)]
public int Fun;

/// <summary>
/// Rank of factor matrices.
/// </summary>
[FieldOffset(4)]
public int K;

/// <summary>
/// Number of threads which can be used for training.
/// </summary>
[FieldOffset(8)]
public int NrThreads;

/// <summary>
/// Number of blocks that the training matrix is divided into. The parallel stochastic gradient
/// method in LIBMF processes assigns each thread a block at one time. The ratings in one block
/// would be sequentially accessed (not randomaly accessed like standard stochastic gradient methods).
/// </summary>
[FieldOffset(12)]
public int NrBins;

/// <summary>
/// Number of training iteration. At one iteration, all values in the training matrix are roughly accessed once.
/// </summary>
[FieldOffset(16)]
public int NrIters;

/// <summary>
/// L1-norm regularization coefficient of left factor matrix.
/// </summary>
[FieldOffset(20)]
public float LambdaP1;

/// <summary>
/// L2-norm regularization coefficient of left factor matrix.
/// </summary>
[FieldOffset(24)]
public float LambdaP2;

/// <summary>
/// L1-norm regularization coefficient of right factor matrix.
/// </summary>
[FieldOffset(28)]
public float LambdaQ1;

/// <summary>
/// L2-norm regularization coefficient of right factor matrix.
/// </summary>
[FieldOffset(32)]
public float LambdaQ2;

/// <summary>
/// Learning rate of LIBMF's stochastic gradient method.
/// </summary>
[FieldOffset(36)]
public float Eta;

/// <summary>
/// Coefficient of loss function on unobserved entries in the training matrix. It's used only with fun=12.
/// </summary>
[FieldOffset(40)]
public float Alpha;

/// <summary>
/// Desired value of unobserved entries in the training matrix. It's used only with fun=12.
/// </summary>
[FieldOffset(44)]
public float C;

/// <summary>
/// Specify if the factor matrices should be non-negative.
/// </summary>
[FieldOffset(48)]
public int DoNmf;
public byte DoNmf;

/// <summary>
/// Set to true so that LIBMF may produce less information to STDOUT.
/// </summary>
[FieldOffset(52)]
public int Quiet;
public byte Quiet;

/// <summary>
/// Set to false so that LIBMF may reuse and modifiy the data passed in.
/// </summary>
[FieldOffset(56)]
public int CopyData;
public byte CopyData;
}

[StructLayout(LayoutKind.Explicit)]
[StructLayout(LayoutKind.Sequential)]
private unsafe struct MFModel
{
[FieldOffset(0)]
/// <summary>
/// See <see cref="MFParameter.Fun"/>.
/// </summary>
public int Fun;

/// <summary>
/// Number of rows in the training matrix.
/// </summary>
[FieldOffset(4)]
public int M;

/// <summary>
/// Number of columns in the training matrix.
/// </summary>
[FieldOffset(8)]
public int N;

/// <summary>
/// Rank of factor matrices.
/// </summary>
[FieldOffset(12)]
public int K;

/// <summary>
/// Average value in the training matrix.
/// </summary>
[FieldOffset(16)]
public float B;

/// <summary>
/// Left factor matrix. Its shape is M-by-K stored in row-major format.
/// </summary>
[FieldOffset(24)] // pointer is 8-byte on 64-bit machine.
public float* P;

/// <summary>
/// Right factor matrix. Its shape is N-by-K stored in row-major format.
/// </summary>
[FieldOffset(32)] // pointer is 8-byte on 64-bit machine.
public float* Q;
}

Expand DownExpand Up@@ -223,9 +229,9 @@ public SafeTrainingAndModelBuffer(IHostEnvironment env, int fun, int k, int nrTh
_mfParam.Eta = (float)eta;
_mfParam.Alpha = (float)alpha;
_mfParam.C = (float)c;
_mfParam.DoNmf = doNmf ? 1 : 0;
_mfParam.Quiet = quiet ? 1 : 0;
_mfParam.CopyData = copyData ? 1 : 0;
_mfParam.DoNmf = doNmf ? (byte)1 : (byte)0;
_mfParam.Quiet = quiet ? (byte)1 : (byte)0;
_mfParam.CopyData = copyData ? (byte)1 : (byte)0;
}

~SafeTrainingAndModelBuffer()
Expand Down
21 changes: 17 additions & 4 deletions src/Native/MatrixFactorizationNative/CMakeLists.txt
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,25 @@
project (MatrixFactorizationNative)
add_definitions(-D_SCL_SECURE_NO_WARNINGS)
add_definitions(-DUSEOMP)
add_definitions(-DUSESSE)

include_directories(libmf)

set(SOURCES
UnmanagedMemory.cpp
libmf/mf.cpp
)
if(UNIX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -O3 -pthread -std=c++0x -march=native")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fopenmp")
if (APPLE)
include_directories("/usr/local/opt/libomp/include")
link_directories("/usr/local/opt/libomp/lib")
endif()
endif()

if(WIN32)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4 /nologo /O2 /EHsc /D \"_CRT_SECURE_NO_DEPRECATE\" /openmp")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}")
endif()

set(SOURCES UnmanagedMemory.cpp libmf/mf.cpp)

if(NOT WIN32)
list(APPEND SOURCES ${VERSION_FILE_PATH})
Expand Down
Loading