Skip to content
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

Fix issue #3612 #4127

Merged
merged 16 commits into from
Jan 29, 2018
25 changes: 25 additions & 0 deletions src/shogun/kernel/CombinedKernel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,31 @@ bool CCombinedKernel::init(CFeatures* l, CFeatures* r)
SG_DEBUG("Initializing 0x%p - \"%s\" (skipping init, this is a CUSTOM kernel)\n", this, k->get_name())
if (!k->has_features())
SG_ERROR("No kernel matrix was assigned to this Custom kernel\n")

// extract row & column subset indices from combined features
auto lhs_subset_stack = ((CCombinedFeatures*)l)->get_subset_stack();
auto rhs_subset_stack = ((CCombinedFeatures*)r)->get_subset_stack();

if (lhs_subset_stack->has_subsets())
{
auto lhs_subset =
lhs_subset_stack->get_last_subset()->get_subset_idx();
// clear all previous subsets
((CCustomKernel*)k)->remove_all_row_subsets();
// apply new subset
((CCustomKernel*)k)->add_row_subset(lhs_subset);
}

if (rhs_subset_stack->has_subsets())
{
auto rhs_subset =
rhs_subset_stack->get_last_subset()->get_subset_idx();
// clear all previous subsets
((CCustomKernel*)k)->remove_all_col_subsets();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you shouldn’t clear the subsets here.
This should happen from outside (and only the last one) as otherwise you might remove stuff a user has set previously

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I operated under the assumption that the subset should be maintained in sync with the combinedfeatures used to init the combinedkernel. Normally, as per my understanding, the subset for the subkernels is obtained from the features used to init them. (The init(features l, features r) method of custom kernel in fact clears the subsets).
As the custom kernel has no features in the 1st place, I attempted to replicate what an init() would do if it had features.
Alternative approach: I could instantiate CIndexFeatures using lhs_subset/rhs_subset, then init the custom kernel using these. This might actually be a better approach, on a second though

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update: There seems to be an inconsistency within CCustomKernel::init(CFeatures* l, CFeatures* r).
Namely, if l & r are of type CIndexFeatures the normalizer doesnt get called, see following block

	if (l->get_feature_class()==C_INDEX && r->get_feature_class()==C_INDEX)
	{
		CIndexFeatures* l_idx = (CIndexFeatures*)l;
		CIndexFeatures* r_idx = (CIndexFeatures*)r;

		remove_all_col_subsets();
		remove_all_row_subsets();

		add_row_subset(l_idx->get_feature_index());
		add_col_subset(r_idx->get_feature_index());

		lhs_equals_rhs=m_is_symmetric;

		return true;
	}

	/* For other types of CFeatures do the default actions below */
	CKernel::init(l, r);

	lhs_equals_rhs=m_is_symmetric;

	SG_DEBUG("num_vec_lhs: %d vs num_rows %d\n", l->get_num_vectors(), kmatrix.num_rows)
	SG_DEBUG("num_vec_rhs: %d vs num_cols %d\n", r->get_num_vectors(), kmatrix.num_cols)
	ASSERT(l->get_num_vectors()==kmatrix.num_rows)
	ASSERT(r->get_num_vectors()==kmatrix.num_cols)
	return init_normalizer();

Is this intentional or not?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most things in there were written in demand if one specific use case, so probably no.

I think everything should be consistent between normal kernels and custom kernels.

So maybe we keep it like this.

Memory check is important before merging though

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not 100% certain what do you mean re: consistency; could you please clarify it to me, perhaps on irc?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry. I meant do it the same way for custom kernels as for normal kernels (clearing the stack)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, so keep the current method, rather than providing dummy indexfeatures, and calling the customkernels init on those? (+ and fix the memory issues)

// apply new subset
((CCustomKernel*)k)->add_col_subset(rhs_subset);
}

if (k->get_num_vec_lhs() != num_lhs)
SG_ERROR("Number of lhs-feature vectors (%d) not match with number of rows (%d) of custom kernel\n", num_lhs, k->get_num_vec_lhs())
if (k->get_num_vec_rhs() != num_rhs)
Expand Down