[docs]classADMMSLIM(GeneralRecommender):input_type=InputType.POINTWISEtype=ModelType.TRADITIONALdef__init__(self,config,dataset):super().__init__(config,dataset)# need at least one paramself.dummy_param=torch.nn.Parameter(torch.zeros(1))X=dataset.inter_matrix(form="csr").astype(np.float32)num_users,num_items=X.shapelambda1=config["lambda1"]lambda2=config["lambda2"]alpha=config["alpha"]rho=config["rho"]k=config["k"]positive_only=config["positive_only"]self.center_columns=config["center_columns"]self.item_means=X.mean(axis=0).getA1()ifself.center_columns:zero_mean_X=X.toarray()-self.item_meansG=zero_mean_X.T@zero_mean_X# large memory cost because we need to make X dense to subtract mean, delete asapdelzero_mean_Xelse:G=(X.T@X).toarray()diag=lambda2*np.diag(np.power(self.item_means,alpha))+rho*np.identity(num_items)P=np.linalg.inv(G+diag).astype(np.float32)B_aux=(P@G).astype(np.float32)# initializeGamma=np.zeros_like(G,dtype=np.float32)C=np.zeros_like(G,dtype=np.float32)deldiag,G# fixed number of iterationsfor_inrange(k):B_tilde=B_aux+P@(rho*C-Gamma)gamma=np.diag(B_tilde)/(np.diag(P)+1e-7)B=B_tilde-P*gammaC=soft_threshold(B+Gamma/rho,lambda1/rho)ifpositive_only:C=(C>0)*CGamma+=rho*(B-C)# torch doesn't support sparse tensor slicing, so will do everything with np/scipyself.item_similarity=Cself.interaction_matrix=X