A multi-view TSK fuzzy system with deformable Gaussian membership functions and rule-level attention for classification.
The 5 matches
- [1] § 4. Experimental design and results analysis › 4.2 Experimental settings ↔ pytsk_MVC/gradient_descent/training.py, lines 78–142 · score 0.76 · weight decay, AdamW, EarlyStopping, split, patience, preprocessing
- [2] § 3. Methodology ↔ pytsk_MVC/gradient_descent/training.py, lines 78–142 · score 0.68 · cross entropy loss, AdamW, optimizer, training, classification, model
- [3] § 4. Experimental design and results analysis › 4.1 Dataset overview ↔ loadDatasets.py, lines 27–65 · score 0.65 · EEG DWT WAV, Handwritten Numerals, Forest, Dermatology, Caltech7
- [4] § 4. Experimental design and results analysis › 4.1 Dataset overview ↔ data.py, lines 67–211 · score 0.62 · EEG DWT WAV, pipeline, Max, Min, Forest, Dermatology
- [5] § 4. Experimental design and results analysis › 4.2 Experimental settings ↔ data.py, lines 67–211 · score 0.58 · EarlyStopping, stratified, split, patience, PyTorch, fitted
Paper
Loaded from Europe PMC by your browser, not stored by OSCR: doi.org · Europe PMC
The paper is loaded when this pane is shown.
The authors' code
Python · 558 lines · 25 KB · no license · 2 matches
- import torch
- import torch.nn as nn
- import torch.optim as optim
- import numpy as np
- from scipy.special import softmax
- from torch.utils.data import DataLoader
- from .utils import NumpyDataLoader
- # loss function
- #--------------------------------------tsk中地UR loss---------------------------------------------------------------------------
- def ur_loss(frs, tau=0.5):
- """
- The uniform regularization (UR) proposed by Cui et al. [3].
- UR loss is computed as :math:`\ell_{UR} = \sum_{r=1}^R (\frac{1}{N}\sum_{n=1}^N f_{n,r} - \tau)^2`,
- where :math:`f_{n,r}` represents the firing level of the :math:`n`-th sample on the :math:`r`-th rule.
- :param torch.tensor frs: The firing levels (output of the antecedent) with the size of :math:`[N, R]`,
- where :math:`N` is the number of samples, :math:`R` is the number of ruels.
- :param float tau: The expectation :math:`\tau` of the average firing level for each rule. For a
- :math:`C`-class classification problem, we recommend setting :math:`\tau` to :math:`1/C`,
- for a regression problem, :math:`\tau` can be set as :math:`0.5`.
- :return: A scale value, representing the UR loss.
- """
- return ((torch.mean(frs, dim=0) - tau) ** 2).sum()
- ## ------------------------------------------TMC中的loss function----------------------------------
- def KL(alpha, c):
- beta = torch.ones((1, c)).cuda()#创建1-tensor,用gpu计算
- S_alpha = torch.sum(alpha, dim=1, keepdim=True)#在某维度求和,并保持整体维度不变
- S_beta = torch.sum(beta, dim=1, keepdim=True)
- '''
- torch.lgamma:
- 一种计算公式
- https://pytorch.org/docs/stable/generated/torch.lgamma.html
- '''
- lnB = torch.lgamma(S_alpha) - torch.sum(torch.lgamma(alpha), dim=1, keepdim=True)
- lnB_uni = torch.sum(torch.lgamma(beta), dim=1, keepdim=True) - torch.lgamma(S_beta)
- '''
- torch.digamma:
- 计算输入的 gamma 函数的对数的导数。
- https://pytorch.org/docs/stable/special.html#torch.special.digamma
- '''
- dg0 = torch.digamma(S_alpha)
- dg1 = torch.digamma(alpha)
- kl = torch.sum((alpha - beta) * (dg1 - dg0), dim=1, keepdim=True) + lnB + lnB_uni
- return kl
- def ce_loss(p, alpha, c, global_step, annealing_step):#交叉熵
- S = torch.sum(alpha, dim=1, keepdim=True)#对输入的tensor数据的某一维度求和,keepdim=True保持求和后维度不变
- E = alpha - 1
- '''
- F.one_hot:
- 独热编码
- https://blog.csdn.net/qq_43760191/article/details/121778553
- ----------------------------------------------------------------------------------
- torch.digamma:
- 计算输入的 gamma 函数的对数的导数。
- https://pytorch.org/docs/stable/special.html#torch.special.digamma
- '''
- label = torch.nn.functional.one_hot(p, num_classes=c)
- A = torch.sum(label * (torch.digamma(S) - torch.digamma(alpha)), dim=1, keepdim=True)
- annealing_coef = min(1, global_step / annealing_step)#取最小值
- alp = E * (1 - label) + 1
- B = annealing_coef * KL(alp, c)
- return (A + B)
- class Wrapper:
- """
- This class provide a training framework for beginners to train their fuzzy neural networks.
- param torch.nn.Module model: The pre-defined TSK model.
- param torch.Optimizer optimizer: Pytorch optimizer.
- :param torch.nn._Loss: Pytorch loss. For example, :code:`torch.nn.CrossEntropyLoss()` for classification tasks,
- and :code:`torch.nn.MSELoss()` for regression tasks.
- :param int batch_size: Batch size during training & prediction.分支大小
- :param int epochs: Training epochs.训练阶段
- :param [Callback] callbacks: List of callbacks.回归列表
- :param str label_type: Label type, "c" or "r", when :code:`label_type="c"`, label's dtype will be changed to
- "int64", when :code:`label_type="r"`, label's dtype will be changed to "float32".
- Examples
- --------
- >>> from pytsk.gradient_descent import antecedent_init_center, AntecedentGMF, TSK, EarlyStoppingACC, EvaluateAcc, Wrapper
- >>> from sklearn.model_selection import train_test_split
- >>> from sklearn.metrics import accuracy_score
- >>> from sklearn.datasets import make_classification
- >>> from sklearn.preprocessing import StandardScaler
- >>> from torch.optim import AdamW
- >>> import torch.nn as nn
- >>> # ----------------- define data -----------------
- >>> X, y = make_classification(random_state=0)
- >>> x_train, x_test, y_train, y_test = train_test_split(X, y, test_size=0.3)
- >>> ss = StandardScaler()
- >>> x_train = ss.fit_transform(x_train)
- >>> x_test = ss.transform(x_test)
- >>> # ----------------- define TSK model -----------------
- >>> n_rule = 10 # define number of rules
- >>> n_class = 2 # define output dimension
- >>> order = 1 # first-order TSK is used
- >>> consbn = True # consbn tech is used
- >>> weight_decay = 1e-8 # weight decay for pytorch optimizer
- >>> lr = 0.01 # learning rate for pytorch optimizer
- >>> init_center = antecedent_init_center(x_train, y_train, n_rule=n_rule) # obtain the initial antecedent center
- >>> gmf = AntecedentGMF(in_dim=x_train.shape[1], n_rule=n_rule, high_dim=True, init_center=init_center) # define antecedent
- >>> model = TSK(in_dim=x_train.shape[1], out_dim=n_class, n_rule=n_rule, antecedent=gmf, order=order, consbn=consbn) # define TSK
- >>> # ----------------- define optimizers -----------------
- >>> ante_param, other_param = [], []
- >>> for n, p in model.named_parameters():
- >>> if "center" in n or "sigma" in n:
- >>> ante_param.append(p)
- >>> else:
- >>> other_param.append(p)
- >>> optimizer = AdamW(
- >>> [{'params': ante_param, "weight_decay": 0}, # antecedent parameters usually don't need weight_decay
- >>> {'params': other_param, "weight_decay": weight_decay},],
- >>> lr=lr
- >>> )
- >>> # ----------------- split 20% data for earlystopping -----------------
- >>> x_train, x_val, y_train, y_val = train_test_split(x_train, y_train, test_size=0.2)
- >>> # ----------------- define the earlystopping callback -----------------
- >>> EACC = EarlyStoppingACC(x_val, y_val, verbose=1, patience=40, save_path="tmp.pkl") # Earlystopping
- >>> TACC = EvaluateAcc(x_test, y_test, verbose=1) # Check test acc during training
- >>> # ----------------- train model -----------------
- >>> wrapper = Wrapper(model, optimizer=optimizer, criterion=nn.CrossEntropyLoss(),
- >>> epochs=300, callbacks=[EACC, TACC], ur=0, ur_tau=1/n_class) # define training wrapper, ur weight is set to 0
- >>> wrapper.fit(x_train, y_train) # fit
- >>> wrapper.load("tmp.pkl") # load best model saved by EarlyStoppingACC callback
- >>> y_pred = wrapper.predict(x_test).argmax(axis=1) # predict, argmax for extracting classfication label
- >>> print("[TSK] ACC: {:.4f}".format(accuracy_score(y_test, y_pred))) # print ACC
- """
- def __init__(self, model, optimizer, criterion,
- batch_size, epochs=1, callbacks=None, label_type="c",
- device="cuda:0", reset_param=True, ur=0, ur_tau=0.5, **kwargs):
- self.model = model
- self.optimizer = optimizer
- self.criterion = criterion
- self.batch_size = batch_size
- self.epochs = epochs
- self.device = device#设置使用gpu or cpu
- self.model.to(self.device)
- self.label_type = label_type
- self.ur = ur
- self.ur_tau = ur_tau
- if callbacks is None:
- self.callbacks = []
- elif isinstance(callbacks, list):#isinstance() 函数来判断一个对象是否是一个已知的类型
- self.callbacks = callbacks
- else:
- raise ValueError("callback must be a Callback object")
- self.reset_param = reset_param
- if self.reset_param:
- self.model.reset_parameters()#重新设置参数
- self.cur_batch = 0
- self.cur_epoch = 0
- self.kwargs = kwargs
- def DS_Combin(self, alpha):
- """
- :param alpha: All Dirichlet distribution parameters.
- :return: Combined Dirichlet distribution parameters.
- """
- def DS_Combin_two(alpha1, alpha2):
- """
- :param alpha1: Dirichlet distribution parameters of view 1
- :param alpha2: Dirichlet distribution parameters of view 2
- :return: Combined Dirichlet distribution parameters
- """
- alpha = dict()#字典
- alpha[0], alpha[1] = alpha1, alpha2#赋值
- b, S, E, u = dict(), dict(), dict(), dict()#字典
- for v in range(2):#
- S[v] = torch.sum(alpha[v], dim=1, keepdim=True)#求和,将维度1求和,并保持维度不变
- E[v] = alpha[v]-1#将所有值减一
- b[v] = E[v]/(S[v].expand(E[v].shape))#拓展维度,将维度中1拓展为E[v].shape
- u[v] = self.model.classes/S[v]#形成(200,1)
- '''
- torch.bmm:--矩阵相乘
- 要求:input 和 mat2 必须是 3-D 张量,每个张量都包含相同数量的矩阵。
- 如果input的维度是( b × n × m ) (b×n×m),mat2维度是( b × m × p ) (b×m×p),
- 那么返回的结果out就是:( b × n × p ) (b×n×p)
- '''
- # b^0 @ b^(0+1)
- bb = torch.bmm(b[0].view(-1, self.model.classes, 1), b[1].view(-1, 1, self.model.classes))
- '''
- torch.mul:
- 是矩阵a和b对应位相乘,比如a的维度是(1, 2),b的维度是(1, 2),返回的仍是(1, 2)的矩阵
- 区别:torch.mm(a, b)是矩阵a和b矩阵相乘,比如a的维度是(1, 2),b的维度是(2, 3),返回的就是(1, 3)的矩阵
- '''
- # b^0 * u^1
- uv1_expand = u[1].expand(b[0].shape)#拓展维度值为1
- bu = torch.mul(b[0], uv1_expand)
- # b^1 * u^0
- uv_expand = u[0].expand(b[0].shape)#拓展维度值为一
- ub = torch.mul(b[1], uv_expand)#矩阵a和b对应位相乘,非矩阵相乘
- '''
- torch.diagonal()
- 对于二维张量就是取对角线元素
- 对于三维张量,比如(6,m, n)
- torch.diagonal(tensor, dim1=-2, dim2=-1) 代表分别取6个m*n张量的对角线元素。
- '''
- # calculate C
- bb_sum = torch.sum(bb, dim=(1, 2), out=None)#将维度求和(200,10,10)-》(200,)
- bb_diag = torch.diagonal(bb, dim1=-2, dim2=-1).sum(-1)#取三维张量的对角线元素,并求和(200,10)-》(200,)
- C = bb_sum - bb_diag
- # calculate b^a
- b_a = (torch.mul(b[0], b[1]) + bu + ub)/((1-C).view(-1, 1).expand(b[0].shape))#torch.mul对应位相乘
- # calculate u^a
- u_a = torch.mul(u[0], u[1])/((1-C).view(-1, 1).expand(u[0].shape))
- # calculate new S
- S_a = self.model.classes / u_a
- # calculate new e_k
- e_a = torch.mul(b_a, S_a.expand(b_a.shape))
- alpha_a = e_a + 1
- return alpha_a
- if(len(alpha)==1):
- return alpha[0]
- for v in range(len(alpha)-1):#
- if v==0:
- alpha_a = DS_Combin_two(alpha[0], alpha[1])
- else:
- alpha_a = DS_Combin_two(alpha_a, alpha[v+1])
- return alpha_a
- def train_on_batch(self, input, target,global_step):
- """
- Define how to update a model with one batch of data.
- This method can be overwrite for custom training strategy.
- :param torch.tensor input: Feature matrix with the size of :math:`[N,D]`,
- :math:`N` is the number of samples, :math:`D` is the input dimension.
- :param torch.tensor target: Target matrix with the size of :math:`[N,C]`,
- :math:`C` is the output dimension.
- """
- # update model once
- target=target.to(self.device)
- for i in range(len(input)):
- input[i] = input[i].to(self.device)#设置训练设备
- #--------------------------------model训练--------------------------------------------------------
- outputs, frs = self.model(input, get_frs=True)
- #--------------------------------loss损失函数-----------------------------------------------
- loss = 0
- alpha = dict()
- ur_loss_value=dict()
- self.cur_epoch=global_step
- for v_num in range(len(input)):
- alpha[v_num] = outputs[v_num] + 1
- loss += ce_loss(target, alpha[v_num], self.model.out_dim, global_step, self.model.lambda_epochs)#损失函数
- # ----------------------------------TSK的UR-----------------------------------
- # if self.ur > 0:
- # ur_loss_value[v_num] = ur_loss(frs[v_num], self.ur_tau)
- # loss += self.criterion(outputs[v_num], target) + self.ur * ur_loss_value[v_num]
- # else:
- # loss += self.criterion(outputs[v_num], target)
- alpha_a = self.DS_Combin(alpha) # 进行了复杂的计算
- evidence_a = alpha_a - 1
- loss += ce_loss(target, alpha_a, self.model.classes, global_step, self.model.lambda_epochs)
- loss = torch.mean(loss) # 求平均
- # if self.ur > 0:
- # ur_loss_value = ur_loss(frs, self.ur_tau)
- # loss = self.criterion(outputs, target) + self.ur * ur_loss_value
- # else:
- # loss = self.criterion(outputs, target)
- '''
- optimizer.zero_grad()
- 意思是把梯度置零,把loss关于weight的导数变成0.
- 当网络参量进行反馈时,梯度是被积累的而不是被替换掉;
- 但是在每一个batch时毫无疑问并不需要将两个batch的梯度混合起来累积,
- 因此这里就需要每个batch设置一遍zero_grad 了
- '''
- self.optimizer.zero_grad()
- loss.backward()## 反向传播,计算当前梯度;
- self.optimizer.step()##根据梯度更新网络参数
- _, preds = torch.max(alpha_a, 1)
- acc = (preds == target).float().mean().item()
- return loss.item(), acc
- preds_list = []
- for v_num in range(len(outputs)):
- out = outputs[v_num] # Tensor [batch_size, n_class]
- _, pred = torch.max(out, 1)
- preds_list.append(pred)
- # alpha_a 已经是融合后的输出,Tensor [batch_size, n_class]
- _, preds = torch.max(alpha_a, 1)
- acc = (preds == target).float().mean().item()
- # if not hasattr(self, "epoch_loss"):
- # self.epoch_loss = 0
- # self.epoch_acc = 0
- # self.batch_count = 0
- def fit(self, X, y):
- """
- Train the :code:`model` with numpy array.
- :param numpy.array X: Feature matrix :math:`X` with the size of :math:`[N, D]`.
- :param numpy.array y: Label matrix :math:`Y` with the size of :math:`[N, C]`,
- for classification task, :math:`C=1`, for regression task, :math:`C` is the
- number of the output dimension of :code:`model`.
- """
- for i in range(len(X)):
- X[i] = X[i].astype("float32")
- if self.label_type == "c":
- y = y.astype("int64")
- elif self.label_type == "r":
- y = y.astype("float32")
- else:
- raise ValueError("label_type can only be \"c\" or \"r\"!")
- '''
- DataLoader
- 就是数据加载器,结合了数据集和取样器,并且可以提供多个线程处理数据集。
- 在训练模型时使用到此函数,用来把训练数据分成多个小组,此函数每次抛出一组数据。直至把所有的数据都抛出。就是做一个数据的初始化。
- batch_size:分支数(分成的小组个数)
- shuffle=True:表示在每个epoch重新打乱洗牌
- num_workers (python:int, optional) – 是否多进程读取数据(默认为0);
- drop_last (bool, optional) – 当样本数不能被batchsize整除时,最后一批数据是否舍弃(default: False)
- '''
- train_loader = DataLoader(
- NumpyDataLoader(X, y),#将 numpy 数组转换为数据加载器
- batch_size=self.batch_size,
- shuffle=self.kwargs.get("shuffle", True),
- num_workers=self.kwargs.get("num_workers", 0),
- drop_last=self.kwargs.get("drop_last", True if self.batch_size < X[0].shape[0] else False),
- )
- self.fit_loader(train_loader)
- return self
- def fit_loader(self, train_loader):
- """
- Train the :code:`model` with user-defined pytorch dataloader.使用用户定义的 pytorch 数据加载器训练。
- :param torch.utils.data.DataLoader train_loader: Data loader, the
- output of the loader should be corresponding to the inputs of :func:`train_on_batch <train_on_batch>`.
- For example, if dataloader has two output, then :func:`train_on_batch <train_on_batch>`
- should also have two inputs.
- """
- self.stop_training = False
- for e in range(self.epochs):
- self.cur_epoch = e#当前迭代次数
- self.epoch_loss = 0
- self.epoch_acc = 0
- self.batch_count = 0
- self.__run_callbacks__("on_epoch_begin")
- #-----------------------------TMC训练部分------------------------------------
- '''
- model.train()
- 就告诉了 BN 层,对之后输入的每个 batch 独立计算其均值和方差,BN 层的参数是在不断变化的。
- 告诉 Dropout 层,你下面应该遮住一神经元
- -------------------------------------------------------------------------------
- '''
- # self.model.train()
- # loss_meter = AverageMeter() # Computes and stores the average and current value
- #-------------------------------------------------------------
- for batch_idx, inputs in enumerate(train_loader):
- self.__run_callbacks__("on_batch_begin") #
- '''
- model.train()
- 就告诉了 BN 层,对之后输入的每个 batch 独立计算其均值和方差,BN 层的参数是在不断变化的。
- 告诉 Dropout 层,你下面应该遮住一神经元
- -------------------------------------------------------------------------------
- '''
- self.model.train()
- # self.train_on_batch(inputs[0], inputs[1], e) # 自定义的训练策略
- batch_loss, batch_acc = self.train_on_batch(inputs[0], inputs[1],self.cur_epoch) # 自定义的训练策略
- self.epoch_loss += batch_loss
- self.epoch_acc += batch_acc
- self.batch_count += 1
- self.__run_callbacks__("on_batch_end")
- self.cur_batch += 1
- self.epoch_loss /= self.batch_count
- self.epoch_acc /= self.batch_count
- self.__run_callbacks__("on_epoch_end")
- if self.stop_training:
- break
- return self
- def predict(self, X,y,global_step):
- """
- Get the prediction of the model.
- :param global_step:
- :param numpy.array X: Feature matrix :math:`X` with the size of :math:`[N, D]`.
- :param y: Not used.
- :return: Prediction matrix :math:`\hat{Y}` with the size of :math:`[N, C]`,
- :math:`C` is the output dimension of the :code:`model`.输出预测的标签y
- """
- for i in range(len(X)):
- X[i] = X[i].astype("float32")
- if self.label_type == "c":
- y = y.astype("int64")
- elif self.label_type == "r":
- y = y.astype("float32")
- else:
- raise ValueError("label_type can only be \"c\" or \"r\"!")
- test_loader = DataLoader(
- NumpyDataLoader(X,y),
- batch_size=self.batch_size,#分支数(分成的小组个数)
- shuffle=False,#表示在每个epoch不重新打乱洗牌
- num_workers=self.kwargs.get("num_workers", 0),# 是否多进程读取数据(默认为0)
- drop_last=False#当样本数不能被batchsize整除时,最后一批数据是否舍弃(default: False)
- )
- Class_preds =[]#用来村类别预测
- loss_meter = AverageMeter()#用来计算loss的平均值
- #----【遍历数据】:将数据分为X个200小组,遍历X次-----------------------------------
- for batch_idx, (inputs,target) in enumerate(test_loader):
- self.model.eval()#告诉BN层不要再变,Dropout层别遮挡当神经元
- for i in range(len(inputs)):
- inputs[i] = inputs[i].to(self.device) # inputs[0]:字典---设置训练设备
- # --------------------------------model预测--------------------------------------------------------
- outputs = self.model(inputs)#inputs[0]:字典--多视图数据
- # --------------------------------loss损失函数-----------------------------------------------
- loss = 0
- alpha = dict()
- target = target.to(self.device)
- for v_num in range(len(inputs)):
- alpha[v_num] = outputs[v_num] + 1
- loss += ce_loss(target, alpha[v_num], self.model.out_dim, global_step, self.model.lambda_epochs) # 损失函数
- alpha_a = self.DS_Combin(alpha) # 进行了复杂的计算--从6个视图结合--》》变为一个视图数据
- evidence_a = alpha_a - 1
- loss += ce_loss(target, alpha_a, self.model.classes, global_step, self.model.lambda_epochs)
- loss = torch.mean(loss) # 求平均
- #----------------挑【evidence_a.data】中【维度为1】最大值作为类别的确定条件-----------------------------------
- _, predicted = torch.max(evidence_a.data, 1) # 返回输入张量维度为1中的元素最大值。
- #------------------------------TMC 计算正确数量,本函数就能计算正确率--------------------------------------
- # correct_num += (predicted == target).sum().item() # 记录正确的次数
- loss_meter.update(loss.item())
- #--------------------------TSk 将预测结果存起来--给上级函数计算正确率----------------------------------------------
- '''
- detach().cpu().numpy():
- 阻断反向传播(因为这里是测试)-将数据从GPU转向CPU-tensor变量转numpy
- 解释:https://blog.csdn.net/weixin_38424903/article/details/107649436
- '''
- predicted =predicted.detach().cpu().numpy()
- Class_preds.append(predicted)#将小组(每个小组200个样本数)的训练后数据存进对应列表(对应视图)中
- '''
- -----结束循环后,获得X个分支预测类别的list,将list合并成一个总和预测数据----------------------------------------
- numpy.concatenate((a1,a2,...), axis=0)
- 函数。能够一次完成多个数组的拼接
- https://www.cnblogs.com/shueixue/p/10953699.html
- '''
- return np.concatenate(Class_preds, axis=0),loss_meter.avg
- def predict_proba(self, X, y=None):
- """
- For classification problem only, need :code:`label_type="c"`, return the prediction after softmax.
- :param numpy.array X: Feature matrix :math:`X` with the size of :math:`[N, D]`.
- :param y: Not used.
- :return: Prediction matrix :math:`\hat{Y}` with the size of :math:`[N, C]`,
- :math:`C` is the output dimension of the :code:`model`.
- """
- if self.label_type == "r":
- raise ValueError("predict_proba can only be used when label_type=\"c\"")
- y_preds = self.predict(X)
- return softmax(y_preds, axis=1)
- def __run_callbacks__(self, func_name):
- for cb in self.callbacks:
- getattr(cb, func_name)(self)#getattr() 函数用于返回一个对象属性值
- def save(self, path):
- """
- Save model.
- :param str path: Model save path.
- """
- torch.save(self.model.state_dict(), path)
- def load(self, path):
- """
- Load model.
- :param str path: Model save path.
- """
- self.model.load_state_dict(torch.load(path))
- class AverageMeter(object):
- """Computes and stores the average and current value"""
- def __init__(self):
- self.reset()
- def reset(self):
- self.val = 0
- self.avg = 0
- self.sum = 0
- self.count = 0
- def update(self, val, n=1):
- self.val = val
- self.sum += val * n
- self.count += n
- self.avg = self.sum / self.count
training.py at commit d466603, no license · at the source
Overview
- School of Artificial Intelligence and Computer Science, Jiangnan University, Wuxi, Jiangsu, China
- Engineering Research Center of the Ministry of Education for Intelligent Technology and Healthcare, Jiangnan University, P.R. China
- Changshu Key Laboratory of Medical Affiliated Intelligence and Big Data, Suzhou, Jiangsu, China
- Center of Intelligent Medical Technology Research, Changshu Hospital Affiliated to Soochow University, Suzhou, Jiangsu, China
Abstract
This study presents a novel multi-view TSK fuzzy system that integrates deformable Gaussian membership functions with a rule-level attention mechanism (MDA-TSK-FS), aiming to improve the modeling capacity and flexibility of fuzzy systems in high-dimensional and complex classification tasks. In the antecedent part, learnable deformation offsets are introduced, enabling the membership function centers of each fuzzy rule to dynamically adjust according to data characteristics. This design enhances the adaptability of rules to the input space. Furthermore, a multi-head attention mechanism at the rule level is incorporated to adaptively allocate rule weights based on sample-specific information, thereby enabling dynamic modeling of rule importance and optimized rule selection. Extensive experiments on five public multi-view datasets, including Caltech7, Handwritten, Dermatology, Forest, and EEG, demonstrate that the proposed model consistently achieves superior performance, reaching classification accuracies of 94.38%, 98.62%, 98.58%, 88.57%, and 69.75%, respectively, and outperforming strong baselines. Ablation studies further verify the effectiveness of the two core components: the deformable antecedent structure and the rule-level attention mechanism, which individually improved EEG classification accuracy by approximately 7% and 6%, and jointly by 9.25% compared to the baseline. Notably, the model exhibits superior generalization and interpretability, particularly when processing multi-source heterogeneous data. These findings indicate that the proposed approach provides a new modeling paradigm for multi-view fuzzy inference, offering both theoretical contributions and practical application potential.
Reproduced under the paper's license (CC BY), from the paper cited above.
Repository
Its files are read in the Code ↔ Paper reader above, with 5 matches between paragraphs and lines of code.
marisazc010/MDA-TSK-FS
d4666030a04d014c757833e1e47a450ad03a3303, 4 March 2026Availability: 1 check, the latest on 28 September 2026: the link answers
- 28 September 2026: the link answers
20 files
- .ipynb_checkpoints/
AntecedentDeformableAtte , Python, 183 linesntionGMF.py - .ipynb_checkpoints/
__init__.py , Python, 1 line - .ipynb_checkpoints/
atten_calu.py , Python, 243 lines - .ipynb_checkpoints/
datavision.py , Python, 556 lines - .ipynb_checkpoints/
loss curve.py , Python, 85 lines - .ipynb_checkpoints/
train_2-checkpoint.py , Python, 500 lines - data.py, Python, 242 lines, 2 matches
- loadDatasets.py, Python, 108 lines, 1 match
- model.py, Python, 226 lines
- pytsk_MVC/
__init__.py , Python, 7 lines - pytsk_MVC/
cluster.py , Python, 310 lines - pytsk_MVC/
gradient_descent/ , Python, 20 lines__init__.py - pytsk_MVC/
gradient_descent/ , Python, 181 linesantecedent.py - pytsk_MVC/
gradient_descent/ , Python, 116 linescallbacks.py - pytsk_MVC/
gradient_descent/ , Python, 558 lines, 2 matchestraining.py - pytsk_MVC/
gradient_descent/ , Python, 88 linestsk.py - pytsk_MVC/
gradient_descent/ , Python, 252 linestsk2.py - pytsk_MVC/
gradient_descent/ , Python, 142 linestsk3.py - pytsk_MVC/
gradient_descent/ , Python, 64 linesutils.py - pytsk_MVC/
test.py , Python, 8 lines
The paper's code and data availability statement is in the Data section.
Tracing map
Proposed by the machine: these links were found in the paper and verified at the source, without human review. The map will receive a Zenodo DOI once one of the paper's authors has validated it with their ORCID.
What the map holds:
- 1 repository of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
- 20 scripts, each with its path and the digest of its content;
- 5 matches between paragraphs of the paper and lines of the code (method lexical-v1);
- neither the text of the paper nor the code itself.
Its JSON (tracing-map.json) is deposited on Zenodo with its DOI once the map is validated.
Data
No dataset and no data link were found in the paper.
Data Availability
All datasets evaluated in this study are publicly accessible from their original sources, including the Caltech Vision Dataset, the UCI Machine Learning Repository, and the PhysioNet Database. To ensure full transparency and reproducibility, the standardized. mat data files, feature representations, and the complete preprocessing scripts are publicly available from the GitHub repository. The complete codebase and materials can be accessed from the GitHub repository (https://
Reproduced under the paper's license (CC BY), from the paper cited above.
Versions
The history of this record: each version stored by the harvester or made by a correction of its authors or of the maintainers of its code, and what changed in its facts. The texts of the paper (its abstract, its availability statements) are not part of it; versions that changed only those are not listed.
Version 2, 28 September 2026
- Funding: added National Natural Science Foundation of China: 62171203; Government of Jiangsu Province
Version 1, 28 September 2026: the first record
Recorded: type, language, journal, volume, issue, pages, dates, 3 authors, 4 MeSH terms, 11 references.
Cite
This paper
Huang, Z., Jiang, Y., & Xia, K. (2026). A multi-view TSK fuzzy system with deformable Gaussian membership functions and rule-level attention for classification. PloS one, 21(5), e0348610. https://
BibTeX
@article{huang2026multi,
author = {Huang, Zhiqi and Jiang, Yizhang and Xia, Kaijian},
title = {{A multi-view TSK fuzzy system with deformable Gaussian membership functions and rule-level attention for classification}},
journal = {PloS one},
year = {2026},
month = may,
volume = {21},
number = {5},
pages = {e0348610},
publisher = {PLOS},
issn = {1932-6203},
doi = {10.1371/
url = {https://
pmid = {42113778},
pmcid = {PMC13160309}
}
RIS
TY - JOUR
AU - Huang, Zhiqi
AU - Jiang, Yizhang
AU - Xia, Kaijian
TI - A multi-view TSK fuzzy system with deformable Gaussian membership functions and rule-level attention for classification
T2 - PloS one
J2 - PLoS One
PY - 2026
DA - 2026/
VL - 21
IS - 5
SP - e0348610
SN - 1932-6203
PB - PLOS
DO - 10.1371/
UR - https://
LA - en
ER -
CSL-JSON
{
"id": "10.1371/
"type": "article-journal",
"title": "A multi-view TSK fuzzy system with deformable Gaussian membership functions and rule-level attention for classification",
"container-title": "PloS one",
"author": [
{
"family": "Huang",
"given": "Zhiqi"
},
{
"family": "Jiang",
"given": "Yizhang"
},
{
"family": "Xia",
"given": "Kaijian"
}
],
"container-title-short":
"volume": "21",
"issue": "5",
"page": "e0348610",
"DOI": "10.1371/
"PMID": "42113778",
"PMCID": "PMC13160309",
"ISSN": "1932-6203",
"publisher": "PLOS",
"URL": "https://
"language": "en",
"issued": {
"date-parts": [
[
2026,
5,
11
]
]
}
}
The tracing map gets a citation of its own once an author has validated it and it has a DOI.
Similar papers
The papers with a page that share the most with this one: the tools found in their code, their categories, datasets, cited references and authors, the rarest counting most.
- [1] doi:10.1038/s42003-026-10169-0 [code]
- Shared representations in brains and models reveal a two-route cortical organization during scene perception.Journal: Communications biologyIn common: h5py, PyTorch, scikit-learn, 4 other tools, 1 reference
- [2] doi:10.7554/elife.110588 [code]
- Opening the black box toward a modular approach to spike sorting.Journal: eLifeIn common: h5py, PyTorch, scikit-learn, 4 other tools, methods / tools
- [3] doi:10.1002/advs.77003 [code]
- SemanticST: A Scalable Multi-Contextual Graph Learning Framework for Uncovering Spatial Niches and Robust Multi-Sample Integration in Spatial Transcriptomics.Journal: Advanced science (Weinheim, Baden-Wurttemberg, Germany)In common: h5py, PyTorch, scikit-learn, 4 other tools, methods / tools
- [4] doi:10.1038/s41467-026-76939-w [code]
- HIPPIE: a generative model for electrophysiological analysis across species, technologies, and modalities.Journal: Nature communicationsIn common: h5py, PyTorch, scikit-learn, 4 other tools, methods / tools
- [5] doi:10.1093/bioinformatics/btag540 [code]
- Deciphering spatial heterogeneity by multimodal spatial transcriptomics modelling with SpatialModal.Journal: Bioinformatics (Oxford, England)In common: h5py, PyTorch, scikit-learn, 4 other tools, methods / tools
- [6] doi:10.1007/s12021-026-09803-3 [code]
- NeuroFusion: A Unified Framework for Generalized Visual Stimulus Decoding from fMRI Across Datasets and Subjects.Journal: NeuroinformaticsIn common: h5py, PyTorch, scikit-learn, 4 other tools, methods / tools
- [7] doi:10.1162/imag.a.1299 [code]
- A modular semantic-structural pipeline for visual decoding from primate spiking data via selective temporal integration.Journal: Imaging neuroscience (Cambridge, Mass.)In common: h5py, PyTorch, scikit-learn, 4 other tools, methods / tools
- [8] doi:10.1016/j.isci.2026.116671 [code]
- A high-resolution functional network-organized atlas of human superficial white matter from ultra-high-field diffusion MRI.Journal: iScienceIn common: h5py, PyTorch, scikit-learn, 4 other tools, methods / tools
- [9] doi:10.1038/s41598-026-57519-w [code]
- Automated segmentation of neurons and spinal cord structures in immunofluorescence images using SpineDL.Journal: Scientific reportsIn common: h5py, PyTorch, scikit-learn, 4 other tools, methods / tools
- [10] doi:10.21203/rs.3.rs-9676637/v1 [code]
- A Comprehensive Benchmarking of Spatial Deconvolution and Domain Detection Methods across Diverse Tissues and Spatial Transcriptomic TechnologiesJournal: Research Square (preprint)In common: h5py, PyTorch, scikit-learn, 4 other tools, methods / tools
Contribute
The authors of this paper can claim it, correct its record and validate its tracing map, and the maintainers of its code (its owner, or a public member of its organization) correct what it says of their repository; anyone signed in can ask for its removal. Every request goes to OSCR's own machine, which answers it; your account page follows them.
Sign in with ORCID to claim this paper as one of its authors, correct its record or validate its tracing map: when the paper's metadata lists your ORCID iD, you are recognized at once. Maintainers of its code: sign in with GitHub, then claim the repository on your account page.
Claim this paper
Correct its record
Say what each link of this record is, remove the ones that are not the paper's, add the ones that are missing. The correction becomes a new version of the record, in its Versions section.
Validate its tracing map
You validate the map as this page shows it: 1 repository of the authors' code, each at its verified commit and with its license, 20 scripts, and 5 matches between paragraphs and code (see the Code and Map sections). It then receives a DOI on Zenodo, with you (your ORCID iD) and OSCR as its creators; the code itself is not deposited.
The map's fingerprint: sha256:17bda0d215e8947c…
Add the badge to its README
The badge links the code to this page. Copy one of these into the README of the paper's code: only you decide where it goes, and nothing is changed for you.
Markdown
[, paste the snippet at the top, then “Commit changes…” and, to review it first, “Create a new branch and start a pull request”. You open the pull request; OSCR asks for no permission.
Request its removal
To ask OSCR to remove this record, the copies of its authors' scripts or its tracing map, use the removal request page: signed in, you say who you are, what to remove and why, then review and confirm the request. Published rules decide every request (how).
Discussion, reproductions, activity
Discussion: questions and error reports about this paper and its code, from signed-in readers and its authors. It opens with sign-in.
Reproductions: reports from readers who ran the authors' code: what they reproduced, with which environment, commit and data. It opens with sign-in.
Activity: what happens around this paper: new versions of its record, its map's validation, discussions and reproductions. It opens with sign-in.
