-
Notifications
You must be signed in to change notification settings - Fork 225
feature: add noise_variance computation on oneDAL side #3101
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
3e518a9
eda0349
2115885
748efc0
2b3156e
614a2f8
9d783b3
4605f46
e2888cf
92ff4c5
19530b8
e18b2bc
553465c
f874b31
0a5658c
79c20ee
9131d60
4675b75
280acf2
10d295b
6112787
be8dc1a
c2e91a7
405ceed
059c802
1ec4172
886bccf
a066d81
1d73325
fd43765
0cc5f37
28318d9
5e23c8e
dbada1d
f6ae492
0a0dce7
46fe403
4e8e2e2
cff7022
6b7cf8f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -171,35 +171,54 @@ services::Status PCACorrelationBase<algorithmFPType, cpu>::computeCorrelationEig | |
|
|
||
| DAAL_OVERFLOW_CHECK_BY_MULTIPLICATION(size_t, nFeatures, nFeatures); | ||
| DAAL_OVERFLOW_CHECK_BY_MULTIPLICATION(size_t, nFeatures * nFeatures, sizeof(algorithmFPType)); | ||
| TArray<algorithmFPType, cpu> matrixCopy(nFeatures * nFeatures); | ||
| DAAL_CHECK_MALLOC(matrixCopy.get()); | ||
|
|
||
| TArray<algorithmFPType, cpu> fullEigenvectors(nFeatures * nFeatures); | ||
| DAAL_CHECK_MALLOC(fullEigenvectors.get()); | ||
| algorithmFPType * fullEigenvectorsArray = fullEigenvectors.get(); | ||
|
|
||
| TArray<algorithmFPType, cpu> fullEigenvalues(nFeatures); | ||
| DAAL_CHECK_MALLOC(fullEigenvalues.get()); | ||
| algorithmFPType * fullEigenvaluesArray = fullEigenvalues.get(); | ||
|
|
||
| copyArray(nFeatures * nFeatures, correlationArray, fullEigenvectorsArray); | ||
|
|
||
| services::Status s = computeEigenvectorsInplace(nFeatures, fullEigenvectorsArray, fullEigenvaluesArray); | ||
| DAAL_CHECK_STATUS_VAR(s); | ||
|
|
||
| s = sortEigenvectorsDescending(nFeatures, fullEigenvectorsArray, fullEigenvaluesArray); | ||
| DAAL_CHECK_STATUS_VAR(s); | ||
| algorithmFPType * matrixArray = matrixCopy.get(); | ||
| copyArray(nFeatures * nFeatures, correlationArray, matrixArray); | ||
|
|
||
| WriteOnlyRows<algorithmFPType, cpu> eigenvectorsBlock(eigenvectors, 0, nComponents); | ||
| DAAL_CHECK_BLOCK_STATUS(eigenvectorsBlock); | ||
| algorithmFPType * eigenvectorsArray = eigenvectorsBlock.get(); | ||
|
|
||
| TArray<algorithmFPType, cpu> fullEigenvalues(nFeatures); | ||
| DAAL_CHECK_MALLOC(fullEigenvalues.get()); | ||
| algorithmFPType * fullEigenvaluesArray = fullEigenvalues.get(); | ||
|
|
||
| WriteOnlyRows<algorithmFPType, cpu> eigenvaluesBlock(eigenvalues, 0, 1); | ||
| DAAL_CHECK_BLOCK_STATUS(eigenvaluesBlock); | ||
| algorithmFPType * eigenvaluesArray = eigenvaluesBlock.get(); | ||
|
|
||
| copyArray(nFeatures * nComponents, fullEigenvectorsArray, eigenvectorsArray); | ||
| copyArray(nComponents, fullEigenvaluesArray, eigenvaluesArray); | ||
| // SYEVR branch | ||
| // In this case, we compute only nComponents eigenvectors and then sort them in descending order | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorting is mentioned in the comment, but there is no sorting in the code. Is it Ok?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The sorting for syevr is already included in computeEigenVectorsInplaceSyevr, but I can split the functions
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To my opinion, it would be better to align the behavior of Otherwise, it is harder to get what's happening in the code.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. All lapack functions for symmetric eigenvalues produce the results in sorted order by design.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I mean descending and ascending ordering sort |
||
| // inside the 'computeEigenvectorsInplaceSyevr' function | ||
| if (nComponents < 0.25 * nFeatures) | ||
| { | ||
| services::Status s = computeEigenvectorsInplaceSyevr(nFeatures, nComponents, matrixArray, fullEigenvaluesArray); | ||
| DAAL_CHECK_STATUS_VAR(s); | ||
|
|
||
| s = sortEigenvectorsDescending(nFeatures, nComponents, matrixArray, fullEigenvaluesArray); | ||
| DAAL_CHECK_STATUS_VAR(s); | ||
|
|
||
| copyArray(nFeatures * nComponents, matrixArray, eigenvectorsArray); | ||
| copyArray(nComponents, fullEigenvaluesArray, eigenvaluesArray); | ||
| return s; | ||
| } | ||
| // SYEVD branch | ||
| // In this case, we compute all eigenvectors and then sort all of them in descending order | ||
| // and copy the first nComponents eigenvectors to the output | ||
| else | ||
| { | ||
| services::Status s = computeEigenvectorsInplace(nFeatures, matrixArray, fullEigenvaluesArray); | ||
| DAAL_CHECK_STATUS_VAR(s); | ||
|
|
||
| s = sortEigenvectorsDescending(nFeatures, nFeatures, matrixArray, fullEigenvaluesArray); | ||
| DAAL_CHECK_STATUS_VAR(s); | ||
|
|
||
| return s; | ||
| copyArray(nFeatures * nComponents, matrixArray, eigenvectorsArray); | ||
| copyArray(nComponents, fullEigenvaluesArray, eigenvaluesArray); | ||
| return s; | ||
| } | ||
| } | ||
|
|
||
| template <typename algorithmFPType, CpuType cpu> | ||
|
|
@@ -223,6 +242,59 @@ services::Status PCACorrelationBase<algorithmFPType, cpu>::computeEigenvectorsIn | |
| return services::Status(); | ||
| } | ||
|
|
||
Alexandr-Solovev marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| template <typename algorithmFPType, CpuType cpu> | ||
| services::Status PCACorrelationBase<algorithmFPType, cpu>::computeEigenvectorsInplaceSyevr(size_t nFeatures, size_t nComponents, | ||
| algorithmFPType * eigenvectors, | ||
| algorithmFPType * eigenvalues) | ||
| { | ||
| char jobz = 'V'; | ||
| char range = 'I'; | ||
| char uplo = 'U'; | ||
|
|
||
| DAAL_INT il = static_cast<DAAL_INT>(nFeatures - nComponents + 1); | ||
| DAAL_INT iu = static_cast<DAAL_INT>(nFeatures); | ||
| DAAL_INT m; | ||
| DAAL_INT info; | ||
|
|
||
| algorithmFPType abstol = -1; | ||
|
|
||
| // Workspace query | ||
| algorithmFPType work_query; | ||
| DAAL_INT iwork_query; | ||
| DAAL_INT lwork = -1; | ||
| DAAL_INT liwork = -1; | ||
|
|
||
| TArray<DAAL_INT, cpu> dummy_isuppz(2); | ||
| DAAL_CHECK_MALLOC(dummy_isuppz.get()); | ||
|
|
||
| LapackInst<algorithmFPType, cpu>::xsyevr(&jobz, &range, &uplo, (DAAL_INT *)(&nFeatures), eigenvectors, (DAAL_INT *)(&nFeatures), nullptr, nullptr, | ||
| &il, &iu, &abstol, &m, nullptr, nullptr, (DAAL_INT *)(&nFeatures), dummy_isuppz.get(), &work_query, | ||
| &lwork, &iwork_query, &liwork, &info); | ||
|
|
||
| lwork = static_cast<DAAL_INT>(work_query); | ||
| liwork = iwork_query; | ||
|
|
||
| TArray<algorithmFPType, cpu> work(lwork); | ||
| TArray<DAAL_INT, cpu> iwork(liwork); | ||
| TArray<DAAL_INT, cpu> isuppz(2 * nComponents); | ||
| DAAL_CHECK_MALLOC(work.get() && iwork.get() && isuppz.get()); | ||
|
|
||
| TArray<algorithmFPType, cpu> temp_eigenvectors(nFeatures * nFeatures); | ||
|
|
||
| LapackInst<algorithmFPType, cpu>::xsyevr(&jobz, &range, &uplo, (DAAL_INT *)(&nFeatures), eigenvectors, (DAAL_INT *)(&nFeatures), nullptr, nullptr, | ||
| &il, &iu, &abstol, &m, eigenvalues, temp_eigenvectors.get(), (DAAL_INT *)(&nFeatures), isuppz.get(), | ||
| work.get(), &lwork, iwork.get(), &liwork, &info); | ||
|
|
||
| if (info != 0 || m != static_cast<DAAL_INT>(nComponents)) | ||
| { | ||
| return services::Status(services::ErrorPCAFailedToComputeCorrelationEigenvalues); | ||
| } | ||
|
|
||
| copyArray(nFeatures * nComponents, temp_eigenvectors.get(), eigenvectors); | ||
|
|
||
| return services::Status(); | ||
| } | ||
|
|
||
| template <typename algorithmFPType, CpuType cpu> | ||
| services::Status PCACorrelationBase<algorithmFPType, cpu>::sortEigenvectorsDescending(size_t nFeatures, algorithmFPType * eigenvectors, | ||
| algorithmFPType * eigenvalues) | ||
|
|
@@ -245,6 +317,46 @@ services::Status PCACorrelationBase<algorithmFPType, cpu>::sortEigenvectorsDesce | |
| return services::Status(); | ||
| } | ||
|
|
||
| template <typename algorithmFPType, CpuType cpu> | ||
| services::Status PCACorrelationBase<algorithmFPType, cpu>::sortEigenvectorsDescending(size_t nFeatures, size_t nComponents, | ||
| algorithmFPType * eigenvectors, algorithmFPType * eigenvalues) | ||
| { | ||
| const algorithmFPType eps = std::numeric_limits<algorithmFPType>::epsilon(); | ||
|
|
||
| for (size_t i = 0; i < nComponents / 2; i++) | ||
| { | ||
| algorithmFPType tmp = eigenvalues[i]; | ||
| algorithmFPType tmp_rev = eigenvalues[nComponents - 1 - i]; | ||
|
|
||
| if (tmp < eps) tmp = algorithmFPType(0); | ||
| if (tmp_rev < eps) tmp_rev = algorithmFPType(0); | ||
|
|
||
| eigenvalues[i] = tmp_rev; | ||
| eigenvalues[nComponents - 1 - i] = tmp; | ||
| } | ||
|
|
||
| if (nComponents % 2 != 0) | ||
| { | ||
| size_t mid = nComponents / 2; | ||
| if (eigenvalues[mid] < eps) | ||
| { | ||
| eigenvalues[mid] = algorithmFPType(0); | ||
| } | ||
| } | ||
|
|
||
| TArray<algorithmFPType, cpu> eigenvectorTmp(nFeatures); | ||
| DAAL_CHECK_MALLOC(eigenvectorTmp.get()); | ||
|
|
||
| for (size_t i = 0; i < nComponents / 2; i++) | ||
| { | ||
| copyArray(nFeatures, eigenvectors + i * nFeatures, eigenvectorTmp.get()); | ||
| copyArray(nFeatures, eigenvectors + nFeatures * (nComponents - 1 - i), eigenvectors + i * nFeatures); | ||
| copyArray(nFeatures, eigenvectorTmp.get(), eigenvectors + nFeatures * (nComponents - 1 - i)); | ||
| } | ||
|
|
||
| return services::Status(); | ||
| } | ||
|
|
||
| } // namespace internal | ||
| } // namespace pca | ||
| } // namespace algorithms | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -163,6 +163,17 @@ static train_result<Task> call_daal_kernel_finalize_train(const context_cpu& ctx | |
| result.set_variances(homogen_table::wrap(arr_vars, 1, column_count)); | ||
| } | ||
|
|
||
| if (desc.get_result_options().test(result_options::noise_variance)) { | ||
| double noiseVariance = 0.0; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. pragmas here too?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think no |
||
| interop::status_to_exception(dal::backend::dispatch_by_cpu(ctx, [&](auto cpu) { | ||
| return daal_pca_cor_kernel_t< | ||
| Float, | ||
| dal::backend::interop::to_daal_cpu_type<decltype(cpu)>::value>() | ||
| .computeNoiseVariances(*daal_eigenvalues, *daal_variances, noiseVariance); | ||
| })); | ||
| result.set_noise_variance(noiseVariance); | ||
| } | ||
|
|
||
| if (desc.get_result_options().test(result_options::explained_variances_ratio)) { | ||
| result.set_explained_variances_ratio( | ||
| homogen_table::wrap(arr_explained_variances_ratio, 1, component_count)); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -126,6 +126,17 @@ static result_t call_daal_kernel(const context_cpu& ctx, | |
| result.set_singular_values(homogen_table::wrap(arr_singular_values, 1, component_count)); | ||
| } | ||
|
|
||
| if (desc.get_result_options().test(result_options::noise_variance)) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this done twice once for batch and once for incremental?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no, in general it should be done once for each of method: |
||
| double noiseVariance = 0.0; | ||
| interop::status_to_exception(dal::backend::dispatch_by_cpu(ctx, [&](auto cpu) { | ||
| return daal_pca_cor_kernel_t< | ||
| Float, | ||
| dal::backend::interop::to_daal_cpu_type<decltype(cpu)>::value>() | ||
| .computeNoiseVariances(*daal_eigenvalues, *daal_variances, noiseVariance); | ||
| })); | ||
| result.set_noise_variance(noiseVariance); | ||
| } | ||
|
|
||
| if (desc.get_result_options().test(result_options::explained_variances_ratio)) { | ||
| result.set_explained_variances_ratio( | ||
| homogen_table::wrap(arr_explained_variances_ratio, 1, component_count)); | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.