Intel® oneAPI Data Analytics Library
Learn from community members on how to build compute-intensive applications that run efficiently on Intel® architecture.

Should the result be transposed in ALS implementation?

Vadim_Karpusenko
Beginner
611 Views

There's potentially a bug in ALS implementation, or I'm doing something wrong. Please, take a look at the code below.

Input data, in CSR format:

[root@c010-n002 DAAL-CF-RS]# cat test.csr 
1,2,3,4
1,1,3
1,1,1

Code (from code examples):

#include "daal.h"
#include "service.h"

using namespace std;
using namespace daal;
using namespace daal::data_management;
using namespace daal::algorithms::implicit_als;

string trainDatasetFileName            = "./test.csv";

typedef double  algorithmFPType;        /* Algorithm floating-point type */
typedef double  dataFPType;             /* Input data floating-point type */

const size_t nFactors = 2;

services::SharedPtr<NumericTable> dataTable;
services::SharedPtr<Model> initialModel;
services::SharedPtr<training::Result> trainingResult;

void initializeModel();
void trainModel();
void testModel();

int main(int argc, char *argv[])
{
    checkArguments(argc, argv, 1, &trainDatasetFileName);
    initializeModel();
    trainModel();
    testModel();
    return 0;
}

void initializeModel()
{
    dataTable = services::SharedPtr<NumericTable>(createSparseTable<dataFPType>(trainDatasetFileName));

    training::init::Batch<algorithmFPType, training::init::fastCSR> initAlgorithm;
    initAlgorithm.parameter.nFactors = nFactors;

    initAlgorithm.input.set(training::init::data, dataTable);

    initAlgorithm.compute();

    initialModel = initAlgorithm.getResult()->get(training::init::model);

    printNumericTable(dataTable, "Initial ratings:");
}

void trainModel()
{
    training::Batch<algorithmFPType, training::fastCSR> algorithm;

    algorithm.input.set(training::data, dataTable);
    algorithm.input.set(training::inputModel, initialModel);

    algorithm.parameter.nFactors = nFactors;

    algorithm.compute();

    trainingResult = algorithm.getResult();
}

void testModel()
{
    prediction::ratings::Batch<> algorithm;
    algorithm.parameter.nFactors = nFactors;

    algorithm.input.set(prediction::ratings::model, trainingResult->get(training::model));

    algorithm.compute();

    services::SharedPtr<NumericTable> predictedRatings = algorithm.getResult()->get(prediction::ratings::prediction);

    printNumericTable(predictedRatings, "Predicted ratings:");
}

Compilation process:

[root@c010-n002 DAAL-CF-RS]# icpc -daal -O3 implicit_als_csr_batch.cpp 
[root@c010-n002 DAAL-CF-RS]# icpc -v
icpc version 16.0.1 (gcc version 4.8.3 compatibility)
[root@c010-n002 DAAL-CF-RS]# ./a.out test.csr 
Initial ratings:
1.000     0.000     0.000     
1.000     0.000     0.000     
0.000     0.000     1.000     

Predicted ratings:
1.000     1.000     -0.009    
0.000     0.000     0.000     
-0.002    -0.002    1.000     

I've tried batch code with CSV files - same result. Looks like the result is transposed... Bug or feature?

 

0 Kudos
6 Replies
VictoriyaS_F_Intel
611 Views

Hello Vadim,

Your observation is correct, the results of ALS prediction are transposed in memory.

This will be fixed in the upcoming release.

Best regards,

Victoriya

0 Kudos
Vadim_Karpusenko
Beginner
611 Views

Thank you, Victoriya.

How would you recommend to transpose the result back? Is this functionality already exists in DAAL, or should I do it manually?

And last quick question: https://software.intel.com/en-us/node/599569 - online DAAL documentation, ALS example. It is a little bit different from the same example in archived documentation from here: https://software.intel.com/en-us/daal-user-and-reference-guides-zip

I'm interested in following code snippet from ZIP archive located at file:///......../daal_ur_guides/daal_cpp_api/implicit_als_dense_batch_8cpp-example.htm#DAAL-EXAMPLE-CPP-IMPLICIT_ALS_DENSE_BATCH

Looks like namespaces were changed, and this file is outdated.

/* file: implicit_als_dense_batch.cpp */
/*******************************************************************************
!  Copyright(C) 2014-2015 Intel Corporation. All Rights Reserved.
!
!  The source code, information  and  material ("Material") contained herein is
!  owned  by Intel Corporation or its suppliers or licensors, and title to such
!  Material remains  with Intel Corporation  or its suppliers or licensors. The
!  Material  contains proprietary information  of  Intel or  its  suppliers and
!  licensors. The  Material is protected by worldwide copyright laws and treaty
!  provisions. No  part  of  the  Material  may  be  used,  copied, reproduced,
!  modified, published, uploaded, posted, transmitted, distributed or disclosed
!  in any way  without Intel's  prior  express written  permission. No  license
!  under  any patent, copyright  or  other intellectual property rights  in the
!  Material  is  granted  to  or  conferred  upon  you,  either  expressly,  by
!  implication, inducement,  estoppel or  otherwise.  Any  license  under  such
!  intellectual  property  rights must  be express  and  approved  by  Intel in
!  writing.
!
!  *Third Party trademarks are the property of their respective owners.
!
!  Unless otherwise  agreed  by Intel  in writing, you may not remove  or alter
!  this  notice or  any other notice embedded  in Materials by Intel or Intel's
!  suppliers or licensors in any way.
!
!*******************************************************************************
!  Content:
!    C++ example of the implicit alternating least squares (ALS) algorithm in
!    the batch processing mode.
!
!    The program trains the implicit ALS model on a dense training data set.
!******************************************************************************/
#include "daal.h"
#include "service.h"
using namespace std;
using namespace daal;
using namespace daal::algorithms::implicit_als;
/* Input data set parameters */
string trainDatasetFileName            = "../data/batch/implicit_als.csv";
typedef double  algorithmFPType;    /* Algorithm floating-point type */
/* Algorithm parameters */
const size_t nUsers = 46;
const size_t nFactors = 2;
const size_t nIndices = 5;
const size_t nRecommendations = 3;
services::SharedPtr<NumericTable> dataTable;
services::SharedPtr<Model> initialModel;
services::SharedPtr<training::Result> trainingResult;
void initializeModel();
void trainModel();
void testModel();
void predictRatings();
int main(int argc, char *argv[])
{
    checkArguments(argc, argv, 1, &trainDatasetFileName);
    initializeModel();
    trainModel();
    predictRatings();
    testModel();
    return 0;
}
void initializeModel()
{
    /* Read trainDatasetFileName from a file and create a numeric table to store the input data */
    FileDataSource<CSVFeatureManager> dataSource(trainDatasetFileName, DataSource::doAllocateNumericTable,
                                                 DataSource::doDictionaryFromContext);
    /* Retrieve the input data */
    dataSource.loadDataBlock(nUsers);
    dataTable = dataSource.getNumericTable();
    /* Create an algorithm object to initialize the implicit ALS model with the default method */
    training::init::Batch<algorithmFPType, training::init::defaultDense> initAlgorithm;
    initAlgorithm.parameter.nFactors = nFactors;
    /* Pass a training data set and dependent values to the algorithm */
    initAlgorithm.input.set(training::init::data, dataTable);
    /* Initialize the implicit ALS model */
    initAlgorithm.compute();
    initialModel = initAlgorithm.getResult()->get(training::model);
}
void trainModel()
{
    /* Create an algorithm object to train the implicit ALS model with the default method */
    training::Batch<algorithmFPType, training::defaultDense> algorithm;
    /* Pass a training data set and dependent values to the algorithm */
    algorithm.input.set(training::data, dataTable);
    algorithm.input.set(training::inputModel, initialModel);
    algorithm.parameter.nFactors = nFactors;
    /* Build the implicit ALS model */
    algorithm.compute();
    /* Retrieve the algorithm results */
    trainingResult = algorithm.getResult();
}
void predictRatings()
{
    /* Create an algorithm object to prediction recommendations of the implicit ALS model */
    prediction::Batch<algorithmFPType, prediction::predictRatingsDense> algorithm;
    algorithm.parameter.nFactors = nFactors;
    algorithm.input.set(prediction::data, dataTable);
    algorithm.input.set(prediction::model, trainingResult->get(training::model));
    algorithm.compute();
    services::SharedPtr<NumericTable> predictedRatings = algorithm.getResult()->get(prediction::ratings);
    printNumericTable(predictedRatings, "Predicted ratings:");
}
void testModel()
{
    /* Create an algorithm object to prediction recommendations of the implicit ALS model */
    prediction::Batch<> algorithm;
    int indices[nIndices] = { 0, 1, 2, 3, 4 };
    services::SharedPtr<NumericTable> indicesTable(new HomogenNumericTable<int>(indices, 1, nIndices));
    algorithm.parameter.nFactors         = nFactors;
    algorithm.parameter.nRecommendations = nRecommendations;
    algorithm.input.set(prediction::indices, indicesTable);
    algorithm.input.set(prediction::model, trainingResult->get(training::model));
    /* Predict recommendations of the implicit ALS model */
    algorithm.compute();
    services::SharedPtr<prediction::Result> predictionResult = algorithm.getResult();
    printNumericTable(predictionResult->get(prediction::itemsIds), "Recommended items IDs:");
    printNumericTable(predictionResult->get(prediction::ratings ), "Recommended items ratings:");
}

Compilation process:

> icpc -daal test.cpp 
test.cpp(76): error: argument of type "daal::algorithms::implicit_als::training::ResultId" is incompatible with parameter of type "daal::algorithms::implicit_als::training::init::ResultId"
      initialModel = initAlgorithm.getResult()->get(training::model);
                                                    ^

test.cpp(94): error: namespace "daal::algorithms::implicit_als::prediction" has no member "Batch"
      prediction::Batch<algorithmFPType, prediction::predictRatingsDense> algorithm;
                  ^

test.cpp(94): error: type name is not allowed
      prediction::Batch<algorithmFPType, prediction::predictRatingsDense> algorithm;
                        ^

test.cpp(94): error: namespace "daal::algorithms::implicit_als::prediction" has no member "predictRatingsDense"
      prediction::Batch<algorithmFPType, prediction::predictRatingsDense> algorithm;
                                                     ^

test.cpp(94): error: identifier "algorithm" is undefined
      prediction::Batch<algorithmFPType, prediction::predictRatingsDense> algorithm;
                                                                          ^

test.cpp(96): error: namespace "daal::algorithms::implicit_als::prediction" has no member "data"
      algorithm.input.set(prediction::data, dataTable);
                                      ^

test.cpp(97): error: namespace "daal::algorithms::implicit_als::prediction" has no member "model"
      algorithm.input.set(prediction::model, trainingResult->get(training::model));
                                      ^

test.cpp(99): error: a namespace name is not allowed
      services::SharedPtr<NumericTable> predictedRatings = algorithm.getResult()->get(prediction::ratings);
                                                                                      ^

test.cpp(105): error: namespace "daal::algorithms::implicit_als::prediction" has no member "Batch"
      prediction::Batch<> algorithm;
                  ^

test.cpp(105): error: expected an expression
      prediction::Batch<> algorithm;
                        ^

test.cpp(108): error: identifier "algorithm" is undefined
      algorithm.parameter.nFactors         = nFactors;
      ^

test.cpp(110): error: namespace "daal::algorithms::implicit_als::prediction" has no member "indices"
      algorithm.input.set(prediction::indices, indicesTable);
                                      ^

test.cpp(111): error: namespace "daal::algorithms::implicit_als::prediction" has no member "model"
      algorithm.input.set(prediction::model, trainingResult->get(training::model));
                                      ^

test.cpp(114): error: namespace "daal::algorithms::implicit_als::prediction" has no member "Result"
      services::SharedPtr<prediction::Result> predictionResult = algorithm.getResult();
                                      ^

test.cpp(115): error: namespace "daal::algorithms::implicit_als::prediction" has no member "itemsIds"
      printNumericTable(predictionResult->get(prediction::itemsIds), "Recommended items IDs:");
                                                          ^

test.cpp(116): error: a namespace name is not allowed
      printNumericTable(predictionResult->get(prediction::ratings ), "Recommended items ratings:");
                                              ^

compilation aborted for test.cpp (code 2)

Can you please show me working example of testModel() function, if it's not too much to ask. Thank you in advance.

0 Kudos
VictoriyaS_F_Intel
611 Views

Vadim,

The latest release of Intel® DAAL doesn't contain transpose functionality. To transpose back the results of ALS prediction you could use following code:

void printTransposedNumericTable(services::SharedPtr<NumericTable> dataTable, const char *message)
{
    size_t nRows = dataTable->getNumberOfRows();
    size_t nCols = dataTable->getNumberOfColumns();

    BlockDescriptor<double> block;
    dataTable->getBlockOfRows(0, nRows, readOnly, block);
    double *data = block.getBlockPtr();
    double *transposedData = new double[nRows * nCols];

    std::cout << std::endl << message << std::endl;
    for (size_t i = 0; i < nRows; i++)
    {
        for (size_t j = 0; j < nCols; j++)
        {
            transposedData[i * nCols + j] = data[j * nRows + i];
            std::cout << std::setw(10) << std::setiosflags(std::ios::fixed) << std::setprecision(3);
            std::cout << transposedData[i * nCols + j];
        }
        std::cout << std::endl;
    }
    dataTable->releaseBlockOfRows(block);
    delete [] transposedData;
}

This function reads the data from input numeric table dataTable, transposes the data and prints the transposed results. transposedData array contains the data in the correct layout.

Regarding the code snippet from ZIP archive. That ZIP archive contains outdated version of the examples. Please refer to Intel® DAAL Programming Guide for the correct version of the examples: https://software.intel.com/en-us/daal-programming-guide

We will remove the outdated version of the codes from the web.

Best regards,

Victoriya

0 Kudos
Vadim_Karpusenko
Beginner
611 Views

Thank you, Victoriya! Your answers are very informative and helpful.

If I may, I would like to ask the last question. For ALS algorithm, is there DAAL's way to get "most recommended" ItemID. Or do I have to check manually all the predicted ratings for particular User to find the corresponding ItemID with the highest rating (or several of them, for instance)?

0 Kudos
VictoriyaS_F_Intel
611 Views

ALS algorithms has one prediction method that computes the ratings for all users and all items based on the trained model. Please refer to the following topic of Intel® DAAL Programming Guide for the description of ALS prediction:

https://software.intel.com/en-us/node/599535

To find the "most recommended" itemID for the user you need to find maximal rating among the ratings computed for this user. The itemID that corresponds to the maximal rating is the "most recommended" itemID.

Best regards,

Victoriya

 

 

0 Kudos
Vadim_Karpusenko
Beginner
611 Views
Right. So, I will have to do extremum search manually. Thank you very much for your help.
0 Kudos
Reply