精华内容
下载资源
问答
  • 原理SVM被提出于1964年,在十世纪90年代后得到快速发展并衍生出一系列改进和扩展算法,在人像识别、文本分类等模式识别(pattern recognition)问题中有得到应用。支持向量机(Support Vector Machine, SVM)是一类按...

    原理

    SVM被提出于1964年,在二十世纪90年代后得到快速发展并衍生出一系列改进和扩展算法,在人像识别、文本分类等模式识别(pattern recognition)问题中有得到应用。

    支持向量机(Support Vector Machine, SVM)是一类按监督学习(supervised learning) 方式对数据进行二元分类的广义线性分类器(generalized linear classifier),其决策边界是对学习样本求解的最大边距超平面(maximum-margin hyperplane)

    SVM可以通过核方法(kernel method)进行非线性分类,是常见的核学习(kernel learning)方法之一。

    分类理论

    在分类问题中给定输入数据和学习目标:X = { X1, X2,…Xn },Y = { y1,y2,…yn}。其中输入数据的每个样本都包含多个特征并由此构成特征空间(feature space):Xi = { x1,x2…xn} ,而学习目标为二元变量y { − 1 , 1 } y\{-1,1\}y{−1,1}表示负类(negative class)和正类(positive class)。

    e3eee4111546d1560d38913d671aac9b.png

    若输入数据所在的特征空间存在作为决策边界(decision boundary)的超平面将学习目标按正类和负类分开,并使任意样本的点到平面距离大于等于1,则称该分类问题具有线性可分性,参数 w,b分别为超平面的法向量和截距。

    b68ee5d94fc1bc2b1cb6dc19d55d5fd8.png

    满足该条件的决策边界实际上构造了2个平行的超平面作为间隔边界以判别样本的分类:

    849311a122586820931f8dd209c10604.png

    所有在上间隔边界上方的样本属于正类,在下间隔边界下方的样本属于负类。两个间隔边界的距离 d = 2 ∥ w ∥ d=\frac{2}{\|w\|}d=∥w∥2​被定义为边距(margin),位于间隔边界上的正类和负类样本为支持向量(support vector)。

    确定最大间距

    我们确定一个分类器,对任意的实数,当w T x + b > 1 , y i = 1 ; w T x + b < − 1 , y i = − 1 w^{T}x+b>1,y_{i}=1;w^{T}x +bwTx+b>1,yi​=1;wTx+b

    这就可以写作:a r g m a x w , b m i n n ( l a b e l ⋅ ( w T + b ) ) ⋅ 1 ∣ ∣ w ∣ ∣ argmax_{w,b}\quad {min_{n}\quad (label⋅(w^{T}+b))⋅\frac{1}{||w||}}argmaxw,b​minn​(label⋅(wT+b))⋅∣∣w∣∣1​。

    很显然l a b e l ⋅ ( w T x i + b ) ⩾ 1 , i = 1 , 2 , . . . , m , label⋅(w^{T}x_{i}+b)⩾1,i=1,2,...,m,label⋅(wTxi​+b)⩾1,i=1,2,...,m,为了最大化间隔只需要最大化∣ ∣ w ∣ ∣ − 1 ||w||^{-1}∣∣w∣∣−1。等价于最小化∣ ∣ w ∣ ∣ 2 ||w||^{2}∣∣w∣∣2。

    因此支持向量机的形式可表示如下:

    1、m i n w , b 1 2 ∣ ∣ w ∣ ∣ 2 min_{w,b} \quad \frac{1}{2}||w||^{2}minw,b​21​∣∣w∣∣2

    2、s . t . y i ( w T x i + b ) ⩾ 1 , i = 1 , 2 , . . . , m . s.t.y_{i}(w^{T}x_{i}+b)⩾1,i=1,2,...,m.s.t.yi​(wTxi​+b)⩾1,i=1,2,...,m.

    最后问题变成了凸二次规划的问题,可解。

    SVM多分类

    SVM算法最初是为二值分类问题设计的,当处理多类问题时,就需要构造合适的多类分类器。目前,构造SVM多类分类器的方法主要有两类:一类是直接法,直接在目标函数上进行修改,将多个分类面的参数求解合并到一个最优化问题中,通过求解该最优化问题“一次性”实现多类分类。这种方法看似简单,但其计算复杂度比较高,实现起来比较困难,只适合用于小型问题中;另一类是间接法,主要是通过组合多个二分类器来实现多分类器的构造,常见的方法有one-against-one和one-against-all两种。

    a.一对多法(one-versus-rest,简称1-v-r-SVMs)。训练时依次把某个类别的样本归为一类,其他剩余的样本归为另一类,这样k个类别的样本就构造出了k个SVM。分类时将未知样本分类为具有最大分类函数值的那类。

    b.一对一法(one-versus-one,简称1-v-1 SVMs)。其做法是在任意两类样本之间设计一个SVM,因此k个类别的样本就需要设计k(k-1)/2个SVM。当对一个未知样本进行分类时,最后得票最多的类别即为该未知样本的类别。Libsvm中的多类分类就是根据这个方法实现的。

    Python实现

    多分类

    X_train, X_test, y_train, y_test = train_test_split(feature, label, test_size=.2,random_state=0)

    # 训练模型

    model = OneVsRestClassifier(svm.SVC(kernel='linear',probability=True,random_state=random_state))

    print("[INFO] Successfully initialize a new model !")

    print("[INFO] Training the model…… ")

    clt = model.fit(X_train,y_train)

    print("[INFO] Model training completed !")

    # 保存训练好的模型,下次使用时直接加载就可以了

    joblib.dump(clt,"F:/python/model/conv_19_80%.pkl")

    print("[INFO] Model has been saved !")

    y_test_pred = clt.predict(X_test)

    ov_acc = metrics.accuracy_score(y_test_pred,y_test)

    print("overall accuracy: %f"%(ov_acc))

    print("===========================================")

    acc_for_each_class = metrics.precision_score(y_test,y_test_pred,average=None)

    print("acc_for_each_class:\n",acc_for_each_class)

    print("===========================================")

    avg_acc = np.mean(acc_for_each_class)

    print("average accuracy:%f"%(avg_acc))

    二分类

    >>> import numpy as np

    >>> X = np.array([[-1, -1], [-2, -1], [1, 1], [2, 1]])

    >>> y = np.array([1, 1, 2, 2])

    >>> from sklearn.svm import SVC

    >>> clf = SVC()

    >>> clf.fit(X, y)

    SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,

    decision_function_shape='ovr', degree=3, gamma='auto', kernel='rbf',

    max_iter=-1, probability=False, random_state=None, shrinking=True,

    tol=0.001, verbose=False)

    >>> print(clf.predict([[-0.8, -1]]))

    [1]

    展开全文
  • 目录:手动实现前馈神经网络、Dropout、正则化、K折交叉验证,解决分类、二分类、回归任务一、实验内容手动实现前馈神经网络完成回归、二分类分类任务利用torch.nn实现前馈神经网络完成回归、二分类分类...

    Pytorch系列文章:

    算法系列文章

    大数据系列文章

    目录:手动实现前馈神经网络、Dropout、正则化、K折交叉验证,解决多分类、二分类、回归任务

    一、实验内容

    手动实现前馈神经网络完成回归、二分类、多分类任务

    本实验的目的是使用前馈神经网络完成分类和回归问题,首先介绍前馈神经网络。对于给定的向量 x = [ x 1 , x 2 , … , x n ] x=\left[x_1,x_2,\ldots,x_n\right] x=[x1,x2,,xn]作为输入,前馈神经网络通过不断迭代以下公式进行信息传播:
    z ( l ) = W ( l ) a ( l − 1 ) + b ( l ) z^{\left(l\right)}=W^{\left(l\right)}a^{\left(l-1\right)}+b^{\left(l\right)} z(l)=W(l)a(l1)+b(l)
    a ( l ) = f l ( z ( l ) ) a^{\left(l\right)}=f_l\left(z^{\left(l\right)}\right) a(l)=fl(z(l))

    其中, a ( l − 1 ) a^{\left(l-1\right)} a(l1)为上一层神经元的输出,且 a ( 0 ) = x a^{\left(0\right)}=x a(0)=x W ( l ) W^{\left(l\right)} W(l)为第l-1层到第l层的权重矩阵; b ( l ) b^{\left(l\right)} b(l)为第l-1层到第l层的偏置; z ( l ) z^{\left(l\right)} z(l)为第l层神经元的输出活性值。然后,活性值经过激活函数得到第l层神经网络的输出 a ( l ) a^{\left(l\right)} a(l)

    若任务为回归问题,可以使用均方误差作为损失函数和评价指标。一般地,若任务为分类问题,则使用Softmax回归计算每一类的概率估计,用交叉熵作为损失,用accuracy作为评价指标。计算出损失后,可利用不同优化器对损失函数进行优化求解。

    利用torch.nn实现前馈神经网络完成回归、二分类、多分类任务

    本部分实验目的是利用Torch.nn库中自带的函数,简洁、高效、模块化地实现实验1.1中的三个任务。

    激活函数对比实验

    激活函数为非线性的复合函数添加了线性的成分,是神经网络逼近函数分布的必要组成。一般地,激活函数需要满足:(1)连续且在多数点上可导;(2)是非线性函数;(3)函数和其导数需要尽可能简单,以加快计算效率;(4)函数和其导数需要落在合适的区间内。

    我们选取了五种激活函数进行实验,他们分别是:

    • Sigmoid函数: σ ( x ) = 1 1 + e x p ( − x ) ∈ ( 0 , 1 ) \sigma\left(x\right)=\frac{1}{1+exp\left(-x\right)}\in\left(0,1\right) σ(x)=1+exp(x)1(0,1)
    • ReLU函数: R e L U ( x ) = m a x [ 0 , x ] ReLU\left(x\right)=max[0,x] ReLU(x)=max[0,x]
    • Tanh函数: t a n h ( x ) = e x p ( x ) − e x p ( − x ) e x p ( x ) + e x p ( − x ) = 2 σ ( 2 x ) − 1 ∈ ( − 1 , 1 ) tanh\left(x\right)=\frac{exp\left(x\right)-exp\left(-x\right)}{exp\left(x\right)+exp\left(-x\right)}=2\sigma\left(2x\right)-1\in\left(-1,1\right) tanh(x)=exp(x)+exp(x)exp(x)exp(x)=2σ(2x)1(1,1)
    • Leaky ReLU函数: L e a k y R e L U ( x ) = { x  if x≥0 γ x if x<0 LeakyReLU\left(x\right) = \begin{cases}x & \text{ if x≥0} \\ γx & \text{if x<0} \end{cases} LeakyReLU(x)={xγx if x≥0if x<0
    • Hard Swish函数: R e L U 6 = m i n ( 6 , m a x ( 0 , x ) ) ReLU6=min\left(6,max\left(0,x\right)\right) ReLU6=min(6,max(0,x)); H s w i s h ( x ) = x R e L U 6 ( x + 3 ) 6 Hswish\left(x\right)=x\frac{ReLU6\left(x+3\right)}{6} Hswish(x)=x6ReLU6(x+3)

    本部分实验目的是对比采用不同激活函数模型对结果的影响。

    隐藏层层数和单元数对比实验

    前馈神经网络中,第0层称为输入层,最后一层称为输出层,其他中间层称为隐藏层。隐藏层层数和单元数是重要的超参数。本部分实验的目的是探究此类超参数对实验结果的影响。

    手动实现、torch.nn实现Dropout

    训练深度神经网络时,可以随机丢弃一部分神经元和此部分对应的连接边以避免过拟合。一般地,对于一个神经层 y = f ( W x + b ) \textbf{y}=f(W\textbf{x}+b) y=f(Wx+b),我们可以引入一个掩蔽函数mask,使得 y = f ( W m a s k ( x ) + b ) \textbf{y}=f(\textbf{W}mask(\textbf{x})+b) y=f(Wmask(x)+b);mask函数通过概率为p的伯努利分布随机生成。

    从集成学习的角度解释,每做一次丢弃,可以认为是采样得到两种新的子网络。若原网络有n个神经元,则总共可以得到 2 n 2^n 2n个共享参数的子网络。本实验的目的是探究dropout对模型训练过程和性能的影响。

    手动实现、torch.nn实现 L 2 \textbf{L}_\mathbf{2} L2正则化

    使用 L 2 L_2 L2正则化时,损失函数中增加加权的模型参数的L_2范数,以限制模型的复杂度,从而提高模型的泛化能力。本实验探究L_2正则化对训练过程和结果的影响。

    手动实现10折交叉验证评估

    10折交叉验证是一种评估模型性能、调整参数的方法。一般地,我们将已有数据分成10份,每次训练时,取其中一份作为验证集,剩余九份作为测试集;共循环十次。10折交叉验证保证每一个样本都作为了训练集、测试集的一部分,能更完整地反映模型的性能。

    二、 实验环境及实验数据集

    本实验在笔记本电脑上开展。笔记本的处理器型号为:Intel® Core™ i7-10510U CPU @ 1.80GHz 2.30 GHz;RAM大小为16GB;系统环境为Windows 64位。程序运行环境是:Anaconda Shell, Python 3.8.10。

    实验包含以下三个数据集:

    • 回归任务数据集:包含10000个数据项\left(\textbf{x},y\right),其中\textbf{x}是维度为500的向量,y是一维数值,服从 y = 0.028 + ∑ i = 1 p 0.056   x i + ε y=0.028+\sum_{i=1}^{p}{0.056{\ x}_i+\varepsilon} y=0.028+i=1p0.056 xi+ε的分布。训练集大小为7000,测试集大小为3000。
    • 二分类任务数据集:包含20000个数据项\left(\textbf{x},y\right),其中:标签为1的数据,\textbf{x}服从均值为10,方差为1的正态分布。
    • 多分类任务数据集:采用MNIST手写体数据集,包含60000个训练样本和10000个测试样本。每个样本是28×28的单通道图像,对应10个数字分类中的一个类。

    三、实验过程

    手动实现前馈神经网络

    与实验一相似,手动实现多层线性模型、交叉熵损失、随机梯度下降来定义模型。由于代码量较大,此处只展示和实验一不同的多层模型的定义部分。

    # 多层神经网络实验用
    W1 = torch.tensor(np.random.normal(1, 1, (256, dim_inputs)), dtype=torch.float)
    b1 = torch.zeros(256, dtype=torch.float32)
    W2 = torch.tensor(np.random.normal(1, 1, (32, 256)), dtype=torch.float)
    b2 = torch.zeros(32, dtype=torch.float32)
    W3 = torch.tensor(np.random.normal(1, 1, (dim_outputs, 32)), dtype=torch.float)
    b3 = torch.zeros(dim_outputs, dtype=torch.float32)
    
    params = [W1,b1,W2,W3,b2,b3]
    
    def net(X):
        X = X.view(-1, dim_inputs)
        out_1 = (torch.matmul(X, W1.t())+b1)
        out_2 = (torch.matmul(out_1, W2.t())+b2)
        out_3 = torch.matmul(out_2, W3.t())+ b3
        return out_3
    

    基于torch.nn实现前馈神经网络

    内容和实验一内容较为相似,不同的是:此次实验中,我们对代码进行了模块化处理,通过传入神经网络层(layer)的列表来构建网络。这种构建方法可以提高代码的复用率,更符合工程开发的范式。
    此小节展示的面向多分类任务的代码也将在二分类和回归任务中复用。
    在这里插入图片描述
    从目录结构我们可以看出,整个程序分为了data、model和network三个模块,分别对应数据预处理、定义模型和模型的构造三个功能。
    model.py是程序的主文件。首先,我们定义适用于多分类问题的网络、参数、数据,并将其作为参数传入在network.py中实现的build_network函数中,以构建网络。

    # 用于多分类
    dim_input = 784
    dim_output = 10
    data = generate_multi_class(batch_size)
    
    # 分类任务网络
    loss = nn.CrossEntropyLoss()
    layers = collections.OrderedDict([
        ('L1',nn.Linear(dim_input,192)),
        ('A1',nn.ReLU()),
        ('drop1',nn.Dropout(p=2)),
        ('L2', nn.Linear(192, 96)),
        ('A2', nn.ReLU()),
        ('drop2', nn.Dropout(p=1)),
        ('FC', nn.Linear(96,dim_output))
    ])
    
    net = build_network(layers)
    
    import torch.optim as opt
    optimizer = opt.Adagrad(net.parameters(),lr=learning_rate,weight_decay=weight_decay)
    

    build_network函数的实现如下:

    def build_network(layers):
        import torch.nn as nn
        net = nn.Sequential(layers)
        return net
    

    网络构建完毕后,在train函数中,完成训练、优化的工作。此处只展示核心代码:

    def train(net, data):
        # parameter: net, *data
        # return train_loss, valid_loss, train_acc, valid_acc
        dataset_train, dataset_test = data
        for epoch in range (1,num_epochs+1,1):
            acc_sum = 0
            cardinatity = 0
            for feature,label in dataset_train:
                prediction = net(feature.view(batch_size,-1))
                l = loss(prediction.squeeze(),label.long())
                l.backward()
                optimizer.step()
                optimizer.zero_grad()
    

    之后,进行模型的评估、可视化、并把评估结果进行储存在csv格式的文件中。其中:evaluate()、calculate()、draw()、store_list()函数的定义均在network.py模块中,函数的实现过程与实验一较为相似,故此处略去展示。对训练代码进行重构后,训练过程更加清晰、简洁。

    	# compute
    	loss_train = evaluate(net,dataset_train,loss,batch_size)
    	loss_test = evaluate(net, dataset_test,loss,batch_size)
    	acc_train = calculate(net, dataset_train,batch_size)
    	acc_test = calculate(net, dataset_test,batch_size)
    	# store
    	train_loss_list.append(loss_train)
    	test_loss_list.append(loss_test)
    	train_acc_list.append(acc_train)
    	test_acc_list.append(acc_test)
    	print("epoch",epoch,"loss_train:",loss_train,"loss_test:",loss_test,"acc_train:", acc_train, "acc_test:", acc_test)
    	# visualize
    	draw_acc(train_acc_list,test_acc_list)
    	draw_loss(train_loss_list,test_loss_list)
    	#store
    	result_list = [train_loss_list,test_loss_list,train_acc_list,test_acc_list]
    	for result in result_list:
    	    store_list(result,retrieve_name(result)[0]
    

    对比不同激活函数的实验结果

    此处,我们只需要对传入build_network()函数的参数layers进行修改。

    layers = collections.OrderedDict([
        ('L1',nn.Linear(dim_input, dim_output)),
        ('A1',nn.Hardswish()), #修改此处的损失函数
    ])
    

    评估隐藏层层数和隐藏单元个数对实验结果的影响

    相似地,我们只需要对传入的列表进行修改。需要注意的是,每一层变换的转化后维数(对应Linear的第二个参数)和下一层的变化的初始维数(对应Linear的第一个参数)需要始终保持一致。此外,dim_input和dim_output代表数据的原始维数、输出的最终维数,需要和数据、问题保持一致。例如对于十分类问题,dim_output为10;对于回归问题,dim_output为1。

    layers = collections.OrderedDict([
        ('L1',nn.Linear(dim_input,192)),
        ('A1',nn.Hardswish()),
        ('L2', nn.Linear(192, 96)),
        ('A2', nn.LeakyReLU()),
        ('FC', nn.Linear(96,dim_output))
    ])
    

    手动实现和用torch.nn实现dropout

    手动实现dropout的基本思想是:随机生成一个mask的0/1矩阵,对权重W作乘法,使得一部分 w i j = 0 w_{ij}=0 wij=0;以此增加模型的鲁棒性。

    def dropout(X,drop_prob):
        X = X.float()
        assert 0<= drop_prob <=1
        keep_prob = 1 - drop_prob
        if keep_prob ==0:
            return torch.zeros_like(X)
        mask = (torch.rand(X.shape)<keep_prob).float()
        return mask * X / keep_prob
    

    需要特别注意的是,dropout只能在训练过程中开启

    def net(X,is_training):
        X = X.view(-1, dim_inputs)
        if is_training:  #训练时开启Dropout
            dropout(W1,drop_prob=1)
        out_1 = (torch.matmul(X, Wt())+b1)
        return out_1
    

    在进行评估(evaluation)时,必须禁止(disable)之前的dropout模块,否则训练使用的只是剪枝后的局部网络。

    def evaluate_test_loss(data_iter,net,loss):
        loss_sum = 0
        count = 0
        for X, y in data_iter:
            yhat = net(X,False)
            l = loss(yhat, y).sum() + lambd *l2_panalty(W1).sum()
            loss_sum += l
            count += y.shape[0]
        return (loss_sum/count).item()
    

    在torch中,使用dropout只需要在layers中额外添加一个dropout层:

    loss = nn.CrossEntropyLoss()
    layers = collections.OrderedDict([
        ('L1',nn.Linear(dim_input,192)),
        ('A1',nn.Hardswish()),
        ('drop1', nn.Dropout(p=1)), # dropout layer 1
        ('L2', nn.Linear(192, 96)),
        ('A2', nn.LeakyReLU()),
        ('drop2', nn.Dropout(p=1)), # dropout layer 2
        ('FC', nn.Linear(96,dim_output))
    ])
    

    手动实现和用torch.nn实现 L 2 \textbf{L}_\mathbf{2} L2正则化

    手动计算参数的 L 2 L_2 L2范数:

    def l2_panalty(w):
        return (w**2)/2
    

    添加到Loss中,实现正则化:

    for X, y in train_iter:
        yhat = net(X,True)
        l = loss(yhat, y).sum() + lambd * l2_panalty(W1).sum() # must sum since l2(W1) is a matrix; loss must be scalar
        for param in params:
              if param.grad is not None:
                  param.grad.data.zero_()
        l.backward()
        SGD(params, lr,batch_size)
    

    在torch中,定义正则化只需要修改优化器的weight_decay参数即可。

    import torch.optim as opt
    optimizer = opt.Adagrad(net.parameters(),lr=learning_rate,weight_decay=weight_decay)
    

    手动实现10折交叉验证评估

    实现10折交叉验证的核心部分代码如下,get_k_fold_data()函数接收特征和标签张量,生成交叉验证的特征和标签。

    def get_k_fold_data(k,i,X,Y,batch_num):
        fold_size = Y.shape[0]// k # int operation
        val_start = i * fold_size
        if i != k-1:
            val_end = (i+1) * fold_size # the next step
            X_valid, Y_valid = X[val_start:val_end], Y[val_start:val_end]
            X_train, Y_train = torch.cat((X[0:val_start],X[val_end:]),dim=0),torch.cat((Y[0:val_start],Y[val_end:]),dim=0)
        else: # add all remaining elements
            X_valid, Y_valid = X[val_start:], Y[val_start:]
            X_train, Y_train = X[0:val_start], Y[0:val_start]
    

    四、实验结果

    多分类任务

    手动实现前馈神经网络

    使用单层线性模型,epochs数为10,batch大小为10,学习率为0.01时,可以观察到训练集、测试集上loss的下降。
    在这里插入图片描述
    由于可能存在的数值方面原因,使用手动实现的多层线性模型进行优化时,Softmax函数的输出趋近于01二项分布,导致损失函数输出值为NaN,无法进行优化。

    利用torch.nn实现前馈神经网络

    使用ReLU作为激活函数的3层前馈神经网络,epochs数为10,batch大小为10,学习率为0.001时,可以观察到训练集、测试集上loss的下降。
    在这里插入图片描述

    对比使用不同激活函数的实验结果

    采用与实验(3)相同的架构,其它激活函数的实验结果如下。
    在这里插入图片描述
    在这里插入图片描述
    对比五种激活函数的实验结果,我们发现:

    • 采用Sigmoid函数时,实验得到的最佳学习率为0.01;相比于ReLU函数使用的学习率更大一些,但效果落后于其它的激活函数。
    • Tanh函数作为激活函数时,loss收敛较快,accuracy较高。
    • Hard Swish函数accuracy上升速度快,后期区域趋势平稳。
    • 收敛时,Hard Swish和Leaky ReLU效果相差较小,是表现最优的两个函数。

    评估隐藏层层数和隐藏单元个数对实验结果的影响

    在这里插入图片描述
    在这里插入图片描述

    手动实现和用torch.nn实现dropout

    手动实现dropout

    在这里插入图片描述由于手动实现的神经网络具有较低的数值稳定性,在dropout率p>=0.2时,会出现Loss为NaN的现象,故实验只记录了两组数据。如上图所示,浅色曲线代表使用dropout后的模型效果,可以发现:使用dropout后,在测试集上的效果随训练次数变化曲线会出现一定的波动,有助于模型避免过拟合。

    利用torch.nn实现dropout

    单层神经网络,使用Sigmoid作为激活函数,不使用Dropout时,表现如下:
    在这里插入图片描述
    可以观察到,此时训练集和测试集的准确率变化基本一致。
    添加Dropout层后,模型表现如下:
    在这里插入图片描述
    在这里插入图片描述
    可以观察到,当dropout率增加到0.3时,测试集上的准确率明显高于训练集。使用更大的训练集、增加训练次数时,dropout的效果可能更充分。

    手动实现和用torch.nn实现L_2正则化

    手动实现 L 2 L_2 L2正则化

    实验中,我们以 λ = 0.2 \lambda=0.2 λ=0.2为参数添加了正则化。可以观察到,添加正则化之后,模型收敛速度迅速提升,在训练集和测试集上的Loss差异大幅减小;但同时,模型的Loss后期趋于稳定,在固定的训练次数下,无法收敛到更高的精度。
    在这里插入图片描述

    torch.nn实现 L 2 L_2 L2正则化

    在这里插入图片描述

    手动实现10折交叉验证评估

    Epoch为10、学习率为0.01、L_2正则化比率设为0.0001、批量数为10时,对以下模型进行训练:
    在这里插入图片描述
    10折交叉验证结果如下:
    在这里插入图片描述

    二分类任务

    手动实现前馈神经网络

    学习率设置为1e-5,批量数为1000,在ReLU函数激活的单层神经网络迭代20次的结果如下
    

    在这里插入图片描述

    利用torch.nn实现前馈神经网络

    采用相同的参数设定,迭代十次的结果如下:
    

    在这里插入图片描述

    实现10折交叉验证评估

    在二分类数据集上得到的结果如下:
    

    在这里插入图片描述

    回归任务

    手动实现前馈神经网络

    学习率设置为1e-3,批量数为200,在Sigmoid函数激活的单层神经网络上迭代20次的结果如下:
    在这里插入图片描述

    利用torch.nn实现前馈神经网络

    在torch实现的前馈神经网络上,迭代10次的结果如下:
    

    在这里插入图片描述

    实现10折交叉验证评估

    在这里插入图片描述

    实验心得体会

    本次实验中,我主要遇到了以下困难和问题:

    • 对torch的索引操作不够熟练。
    • 在参数调试上消耗了大量时间。
    • 对于原始数据的格式问题没有引起重视,因此引发了很多的bug,消耗了大量时间。
    • 没有从一开始就进行模块化设计、养成把结果数据保存以备后续使用的意识。
    • 最开始计算对模型的评估时,没有去除dropout模块;后期改正之后才得到满意的结果。
      以上问题让本次实验困难重重,但都一一解决。在后续的学习中,我会重视以上问题,不断迭代更新,更熟练地完成此类程序的设计。

    写文不易,欢迎投喂:
    在这里插入图片描述

    展开全文
  • 机器学习二分类模型评价指标详述

    千次阅读 2021-01-10 17:32:37
    注:既然Precision与Recall都是二分类指标,则PR曲线也必然是二分类指标,虽然可以将precision、Recall及PR曲线应用到分类,但是这种情况相当于是分类转换为二分类情况分析(将关注的类视为一类,将其他所有类...

    问题建模

    机器学习解决问题的通用流程:问题建模——特征工程——模型选择——模型融合

    其中问题建模主要包括:设定评估指标,选择样本,交叉验证

    解决一个机器学习问题都是从问题建模开始,首先需要收集问题的资料,深入理解问题,然后将问题抽象成机器可预测的问题。在这个过程中要明确业务指标模型预测目标,根据预测目标选择适当指标用于模型评估。接着从原始数据中选择最相关的样本子集用于模型训练,并对样本子集划分训练集和测试集,应用交叉验证的方法对模型进行选择和评估。

    评估指标

    评估指标很多,我们应该选择一个能跟业务指标波动一致的评估指标,这样通过观察评估指标就能判断模型效果,可以大大提高模型迭代效率。

    评估指标用于反应模型效果,在预测问题中,要评估模型的效果,就需要将模型预测结果 f(x) ​和真真实标注 Y​ 进行比较,评估指标定义为f(x)Y​的函数。

    score = metric(f(x),Y)

    通常线下使用的是机器学习评估指标,线上使用的是业务指标,如果线下指标和线上指标不同,则可能会出现线下指标变好而线上指标变差的现象。为此,在一个新问题的开始阶段,都会进行多轮模型迭代,来探索和线上业务指标一致的线下指标,尽可能使线下指标的变趋势和线上指标一致

    分类指标

    1. 精确率、召回率、准确率、错误率和F函数

    1.1 精确率和召回率

    精确率和召回率主要用于二分类问题(从其公式推导也可看出),结合混淆矩阵有:

     

    精确率P和召回率R的定义为:

    精确率(Precision) = \frac{True \ Positive}{True \ Positive + False \ Positive}

    召回率(Recall) = \frac{True \ Positive}{True \ Positive + False \ Negative}

     

    上述计算公式中的Positive与Negative是预测标签,True与false代表预测正误;
    要注意,精确率和召回率是二分类指标,不适用多分类,由此得到P-R曲线以及ROC曲线均是二分类评估指标(因为其横纵轴指标均为二分类混淆矩阵计算得到),而准确率适用于多分类评估。(可以将多分类问题转换为二分类问题进行求解,将关注的类化为一类,其他所有类化为一类)

    理想情况下,精确率和召回率两者都越高越好。然而事实上这两者在某些情况下是矛盾的,精确率高时,召回率低;精确率低时,召回率高;关于这个性质通过观察PR曲线不难观察出来。比如在搜索网页时,如果只返回最相关的一个网页,那精确率就是100%,而召回率就很低;如果返回全部网页,那召回率为100%,精确率就很低。因此在不同场合需要根据实际需求判断哪个指标跟重要。

    上图分析一下:

     

     

    • recall是相对真实的答案而言: true positive / golden set 。假设测试集里面有100个正例,你的模型能预测覆盖到多少,如果你的模型预测到了40个正例,那你的recall就是40%。
    • precision是相对你自己的模型预测而言:true positive /retrieved set。假设你的模型一共预测了100个正例,而其中80个是对的正例,那么你的precision就是80%。我们可以把precision也理解为,当你的模型作出一个新的预测时,它的confidence score 是多少,或者它做的这个预测是对的的可能性是多少。
    • 一般来说呢,鱼与熊掌不可兼得。如果你的模型很贪婪,想要覆盖更多的sample,那么它就更有可能犯错。在这种情况下,你会有很高的recall,但是较低的precision。如果你的模型很保守,只对它很sure的sample作出预测,那么你的precision会很高,但是recall会相对低。

    这样一来呢,我们可以选择只看我们感兴趣的class,就是minority class的precision,recall来评价模型的好坏。

    1.2 准确率和错误率

    准确率和错误率既可用于二分类也可用于多分类:

    准确率(accuracy)= \frac{TP+TN}{TP+FP+FN+TN}

    错误率(error rate) = \frac{FP+FN}{TP+FP+FN+TN}

     

    上述公式是准确率、错误率针对二分类情况时候的计算公式

    精确率和准确率是比较容易混淆的两个评估指标,两者是有区别的。精确率是一个二分类指标,而准确率能应用于多分类,其计算公式为:

     

    准确率(accuracy) = \frac{1}{n}\sum_{i=1}^{n}I(f(x_i)=y_i)

     

    1.3F函数:

    F1函数是一个常用指标,F1值是精确率和召回率的调和均值,即

     

    \frac{2}{F_1} = \frac{1}{P} + \frac{1}{R}

     

    F_1 = \frac{2PR}{P+R}

     

    F值可泛化为对精确率和召回率赋不同权值进行加权调和:

     

    F_{\alpha} = \frac{(1+\alpha^2) PR}{\alpha^2 P+R}

     

     

    利用 \alpha 给P和R赋予不同的权重,若 \alpha = 1 则为F1值。

    下面是两个场景:

    1. 地震的预测对于地震的预测,我们希望的是RECALL非常高,也就是说每次地震我们都希望预测出来。这个时候我们可以牺牲PRECISION。情愿发出1000次警报,把10次地震都预测正确了;也不要预测100次对了8次漏了两次。
    2. 嫌疑人定罪基于不错怪一个好人的原则,对于嫌疑人的定罪我们希望是非常准确的。及时有时候放过了一些罪犯(recall低),但也是值得的。对于分类器来说,本质上是给一个概率,此时,我们再选择一个CUTOFF点(阀值),高于这个点的判正,低于的判负。那么这个点的选择就需要结合你的具体场景去选择。反过来,场景会决定训练模型时的标准,比如第一个场景中,我们就只看RECALL=99.9999%(地震全中)时的PRECISION,其他指标就变得没有了意义。

    2. ROC曲线、PR曲线

    2.1 PR曲线

    我们以召回率R为横轴、以精确率P为纵轴,能够画出P-R曲线,如下图:

     

    从上图不难发现,precision与Recall的折中(trade off),曲线越靠近右上角性能越好,曲线下的面积叫AP分数,能在一定程度上反应模型的精确率和召回率都很高的比例。但这个值不方便计算,综合考虑精度与召回率一般使用F1函数或者AUC值(因为ROC曲线很容易画,ROC曲线下的面积也比较容易计算).

    先看平滑不平滑,在看谁上谁下(同一测试集上),一般来说,上面的比下面的好(红线比黑线好);

    F1(计算公式略)当P和R接近就也越大,一般会画连接(0,0)和(1,1)的线,线和PRC重合的地方的F1是这条线最大的F1(光滑的情况下),此时的F1对于P-R曲线就好象AUC对于ROC一样。一个数字比一条线更方便调模型。

    注:既然Precision与Recall都是二分类指标,则PR曲线也必然是二分类指标,虽然可以将precision、Recall及PR曲线应用到多分类,但是这种情况相当于是多分类转换为二分类情况分析(将关注的类视为一类,将其他所有类化为一类)

    2.2 ROC曲线

    在众多的机器学习模型中,很多模型输出的是预测概率,而使用精确率、召回率这类指标进行模型评估时,还需要对预测概率设分类阈值,比如预测概率大于阈值为正例,反之为负例。这使得模型多了一个超参数,并且这超参数会影响模型的泛化能力。

    接受者操作特征(Receiver Operating Characteristic, ROC)曲线不需要设定这样的阈值,ROC曲线纵坐标是真正率,横坐标是假正率,如下图,去对应的计算公式为:

     

    真正率(True \ Positive \ Rate) = \frac{TP}{TP+FN}

     

    假正率(False \ Positive \ Rate) = \frac{FP}{FP+TN}

     

    同时,TPR与FPR又有其他名称,如下:

    • sensitivity = recall = true positive rate
    • specificity = 1- false positive rate

    假设我们的minority class,也就是正例,是1。反例,为0。$\hat{Y}$是真实label Y的估计(estimate)。

     

    看出来没有,sensitivity和specificity是条件于真实label Y的概率的。我们讲这个叫条件概率嘛。那么意思就是说,无论Y的真实概率是多少,都不会影响sensitivity和specificity。也就是说,这两个metric是不会受imbalanced data 影响的,那就很客观了啊,是不是!而precision呢,就会随着你的测试集里面的正反比例而变化哦。

    另外值得注意的是, AUC的计算方法同时考虑了学习器对于正例和负例的分类能力,在样本不平衡的情况下,依然能够对分类器做出合理的评价。AUC对样本类别是否均衡并不敏感,这也是不均衡样本通常用AUC评价学习器性能的一个原因。

    例如在癌症预测的场景中,假设没有患癌症的样本为正例,患癌症样本为负例,负例占比很少(大概0.1%),如果使用准确率评估,把所有的样本预测为正例便可以获得99.9%的准确率。但是如果使用AUC,把所有样本预测为正例,TPR为1,FPR为1。这种情况下学习器的AUC值将等于0.5,成功规避了样本不均衡带来的问题。

    这个曲线就是以true positive rate 和 false positive rate为轴,取不同的threshold点画的啦。有人问了,threshold是啥子哦。这么说吧,每个分类器作出的预测呢,都是基于一个probability score的。一般默认的threshold呢都是0.5,如果probability>0.5,那么这个sample被模型分成正例了哈,反之则是反例。

     

    真正率(True Positive Rate)就是召回率Recall

    ROC曲线和P-R曲线有些类似,ROC曲线越靠近左上角性能越好。左上角坐标为(0, 1),即FPR=0,TPR=1,根据FPR和TPR公可以得知,此时FN=0, FP=0,模型对所有样本分类正确,绘制ROC曲线很简单,首先对所有样本按预测概率排序,以每条样本的预测概率为阈值,计算相应的FPR和TPR,然后线段连接。

    当数据量少时,绘制的ROC曲线不平滑;当数据量大时,绘制的ROC曲线会趋于平滑。

    ROC curve 可以很好的回答什么问题呢——“不论class的基本概率怎么样,我的模型in general能表现得多好?”

    一般来说呢,最优的threshold就是橙色曲线离蓝色虚线(基准线)最远的一点啦,或者橙色曲线上离左上角最近的一点,再或者是根据用户自己定义的cost function来的。

    一般来说,如果ROC是光滑的,那么基本可以判断没有太大的overfitting(比如图中0.2到0.4可能就有问题,但是样本太少了),这个时候调模型可以只看AUC,面积越大一般认为模型越好。

    1. 主要作用

    1. ROC曲线能很容易的查出任意阈值对学习器的泛化性能影响。
    2. 有助于选择最佳的阈值。ROC曲线越靠近左上角,模型的查全率就越高。最靠近左上角的ROC曲线上的点是分类错误最少的最好阈值,其假正例和假反例总数最少。
    3. 可以对不同的学习器比较性能。将各个学习器的ROC曲线绘制到同一坐标中,直观地鉴别优劣,靠近左上角的ROC曲所代表的学习器准确性最高。

    2. 优点

    1. 该方法简单、直观、通过图示可观察分析方法的准确性,并可用肉眼作出判断。ROC曲线将真正例率和假正例率以图示方法结合在一起,可准确反映某种学习器真正例率和假正例率的关系,是检测准确性的综合代表。
    2. 在生物信息学上的优点:ROC曲线不固定阈值,允许中间状态的存在,利于使用者结合专业知识,权衡漏诊与误诊的影响,选择一个更加的阈值作为诊断参考值。

    3. AUC

    3.1 什么是AUC

    AUC是一个模型评价指标,只能用于二分类模型的评价,对于二分类模型,还有很多其他评价指标,比如logloss,accuracy,precision。如果你经常关注数据挖掘比赛,比如kaggle,那你会发现AUC和logloss基本是最常见的模型评价指标。为什么AUC和logloss比accuracy更常用呢?因为很多机器学习的模型对分类问题的预测结果都是概率,如果要计算accuracy,需要先把概率转化成类别,这就需要手动设置一个阈值,如果对一个样本的预测概率高于这个预测,就把这个样本放进一个类别里面,低于这个阈值,放进另一个类别里面。所以这个阈值很大程度上影响了accuracy的计算。使用AUC或者logloss可以避免把预测概率转换成类别。

    AUC是Area under curve的首字母缩写。AUC就是ROC曲线下的面积,衡量学习器优劣的一种性能指标。从定义可知,AUC可通过对ROC曲线下各部分的面积求和而得。假定ROC曲线是由坐标为 {(x_1, y_1), (x_2, y_2), (x_3, y_3), \cdots, (x_m, y_m)} 的点按序连接而形成,则AUC可估算为:

     

    AUC = \frac{1}{2}\sum_{i=1}^{m-1}(x_{i+1} - x_i)(y_i + y_{i+1})

    3.2 AUC的意义

    通过AUC的定义我们知道了AUC是什么,怎么算,但是它的意义是什么呢。如果从定义来理解AUC的含义,比较困难,实际上AUC和Mann–Whitney U test有密切的联系。

    从Mann–Whitney U statistic的角度来解释,AUC就是从所有1样本中随机选取一个样本, 从所有0样本中随机选取一个样本,然后根据你的分类器对两个随机样本进行预测,把1样本预测为1的概率为p1,把0样本预测为1的概率为p0,p1>p0的概率就等于AUC。

    AUC是指随机给定一个正样本和一个负样本,分类器输出该正样本为正的那个概率值比分类器输出该负样本为正的那个概率值要大的可能性。

    所以AUC反应的是分类器对样本的排序能力。根据这个解释,如果我们完全随机的对样本分类,那么AUC应该接近0.5。(所以一般训练出的模型,AUC>0.5,如果AUC=0.5,这个分类器等于没有效果,效果与完全随机一样,如果AUC<0.5,则可能是标签标注错误等情况造成);

    另外值得注意的是,AUC的计算方法同时考虑了学习器对于正例和负例的分类能力,在样本不平衡的情况下,依然能够对分类器做出合理的评价。AUC对样本类别是否均衡并不敏感,这也是不均衡样本通常用AUC评价学习器性能的一个原因。

    这个指标尤其适用在某些场景下(如 CTR 预估),每次要返回的是最有可能点击的若干个广告(根据CTR排序, 选择排在前面的若干个),实际上便是在考验模型的排序能力。除此之外,CTR 中存在着样本不均衡的问题,正负样本比例通常会大于 1:100,如果采用 PR 曲线,则会导致 AUC 发生剧变,无法较好反映模型效果。

    然而,ROC 曲线不会随着类别分布的改变而改变的优点在一定程度上也是其缺点。因为 ROC 曲线这种不变性其实影响着的是 AUC 值,或者说是评估分类器的整体性能。但是在某些场景下,我们会更关注正样本,这时候就要用到 PR 曲线了。

    比如说信用卡欺诈检测,我们会更关注 precision 和 recall,比如说如果要求预测出为欺诈的人尽可能准确,那么就是要提高 precision;而如果要尽可能多地预测出潜在的欺诈人群,那么就是要提高 recall。一般来说,提高二分类的 threshold 就能提高 precision,降低 threshold 就能提高 recall,这时便可观察 PR 曲线,得到最优的 threshold。

    此外,AUC和Wilcoxon Test of Ranks等价;AUC还和基尼(Gini)系数有联系,满足

    Gini+1 = 2*AUC

     

    3.3 AUC的计算方法:

    AUC的计算方法有多种,从物理意义角度理解,AUC计算的是ROC曲线下的面积:

     

    AUC = \sum_{i \in (P+N)}\frac{(TPR_i + TPR_{I-1})*(FPR_i - FPR_{i-1})}{2}

     

    从概率意义角度理解,AUC考虑的是样本的排序质量,它与排序误差有密切关系,可得到计算公式:

    AUC = \frac{\sum_{i \in P}rank_i - \frac{|P|(|P|+1)}{2}}{|P||N|}

     

    其中,rank为样本排序位置从1开始, |P| 为正样本数, |N| 为负样本数。

    AUC计算主要与排序有关,所以它对排序敏感,而对预测分数没那么敏感。

    最后,我们在讨论一下:在多分类问题下能不能使用ROC曲线来衡量模型性能?

    我的理解:ROC曲线用在多分类中是没有意义的。只有在二分类中Positive和Negative同等重要时候,适合用ROC曲线评价。如果确实需要在多分类问题中用ROC曲线的话,可以转化为多个“一对多”的问题。即把其中一个当作正例,其余当作负例来看待,画出多个ROC曲线。

    “ROC 曲线具有不随样本比例而改变的良好性质,因此能够在样本比例不平衡的情况下较好地反映出分类器的优劣。”
    AUC计算主要与排序有关,所以他对排序敏感,而对预测分数没那么敏感。

    4. 对数损失

    对数损失(logistic loss,logloss)是对预测概率的似然估计,其标准形式为:

     

    logloss = -logP(Y|X)

     

    对数损失最小化本质上是利用样本中的已知分布,求解导致这种分布的最佳模型参数,是这种分布出现概率最大。

    对数损失对应的二分类的计算公式为:

     

    logloss = -\frac{1}{N}\sum_{i=1}^{N}(y \cdot logp_i + (1-y) \cdot log(1-p_i))

     

    其中, y \in \{0,1\} , p_i 为第 i 条样本预测为1的概率。

    对数损失在多分类问题中也使用广泛,其计算公式为:

     

    logloss = - \frac{1}{N}\cdot \frac{1}{C} \cdot \sum_{i=1}^{N} \sum_{j=1}^{C} y_{ij}\cdot logp_{ij}

     

    其中, N 为样本数, C 为类别数, y_{ij} = 1 表示第$i$条样本的类别为 j , p_{ij} 为第 i 条样本类别 j 的概率。

    logloss衡量的是预测概率分布和真实概率分布的差异性,取值越小越好。与AUC不同,logloss对预测概率敏感。

    总结

    1. 精确率(Precision)是指在所有系统判定的“真”的样本中,确实是真的的占比,就是TP/(TP+FP)。
    2. 召回率(Recall)是指在所有确实为真的样本中,被判为的“真”的占比,就是TP/(TP+FN)。
    3. TPR(True Positive Rate)的定义,跟Recall一样。
    4. FPR(False Positive Rate),又被称为“Probability of False Alarm”,就是所有确实为“假”的样本中,被误判真的样本,或者FP/(FP+TN)
    5. F1值是为了综合考量精确率和召回率而设计的一个指标,一般公式为取P和R的harmonic mean:2PrecisionRecall/(Precision+Recall)。
    6. ROC=Receiver Operating Characteristic,是TPR vs FPR的曲线;与之对应的是Precision-Recall Curve,展示的是Precision vs Recall的曲线。

    参考资料:

    1. 机器学习和统计里面的AUC如何理解
    2. 精确率、召回率、F1 值、ROC、AUC 各自的优缺点是什么?
    3. 美团机器学习实践
    4. ROC 曲线与 PR 曲线
    展开全文
  • logistic回归是一个二分类模型

    万次阅读 2021-03-09 16:54:52
    首先给大家强调一点,这是一个分类模型而不是一个回归模型!下文开始将从不同方面讲解logistic回归的原理,随后分别使用梯度上升算法和随机梯度上升算法将logistic回归算法应用到实例中。 一、logistic回归和线性...

    logistic回归,又叫对数几率回归(从后文中便可此名由来)。首先给大家强调一点,这是一个分类模型而不是一个回归模型!下文开始将从不同方面讲解logistic回归的原理,随后分别使用梯度上升算法和随机梯度上升算法将logistic回归算法应用到实例中。


    一、logistic回归和线性回归的关系

    想必大家也早有疑惑,既然logistic回归名字中都带有“回归”二者,难道和回归模型一点关系都没有!没错,二者是有联系的,下面我们便来谈一谈!

    首先给出线性回归模型: 

    这里写图片描述


    写成向量形式为: 

    这里写图片描述


    同时“广义线性回归”模型为: 

    这里写图片描述


    注意,其中g(~)是单调可微函数。

     

    下面我们便从线性回归的回归模型引出logistic回归的分类模型!!!

    我们知道上诉线性回归模型只能够进行回归学习,但是若要是做分类任务如何做!答案便是在“广义线性回归”模型中:只需找一个单调可微函数将分类任务的真实标记y与线性回归模型的预测值联系起来便可以了!

    logistic回归是处理二分类问题的,所以输出的标记y={0,1},并且线性回归模型产生的预测值z=wx+b是一个实值,所以我们将实值z转化成0/1值便可,这样有一个可选函数便是“单位阶跃函数”: 

    这里写图片描述


    这种如果预测值大于0便判断为正例,小于0则判断为反例,等于0则可任意判断!

     

    但是单位阶跃函数是非连续的函数,我们需要一个连续的函数,“Sigmoid函数”便可以很好的取代单位阶跃函数: 

    这里写图片描述


    sigmoid函数在一定程度上近似单位阶跃函数,同时单调可微,图像如下所示: 

    这里写图片描述

     

    这样我们在原来的线性回归模型外套上sigmoid函数便形成了logistic回归模型的预测函数,可以用于二分类问题: 

    这里写图片描述


    对上式的预测函数做一个变换为: 

    这里写图片描述


    观察上式可得: 若将y视为样本x作为正例的可能性,则1-y便是其反例的可能性。二者的比值便被称为“几率”,反映了x作为正例的相对可能性,这也是logistic回归又被称为对数几率回归的原因!

     

    这里我们也便可以总结一下线性回归模型和logistic回归的关系: 
    logistic回归分类模型的预测函数是在用线性回归模型的预测值的结果去逼近真实标记的对数几率!这样也便实现了上面说的将线性回归的预测值和分类任务的真实标记联系在了一起!


    二、梯度上升算法求解logistic回归模型参数w

    在上一个话题中我们已经得到了logistic回归的预测函数: 

    这里写图片描述

     

    这里写图片描述

     

    这里我们将式子中的y视为类后验概率估计p(y=1|x),则上式可以重写为: 

    这里写图片描述


    求解上式有: 

    这里写图片描述

     

    这里写图片描述

     

    先给出求解参数w的思路,下面我们便按照这个思路进行求解参数w: 
    1、为求解参数w,我们需要定义一个准则函数 J(w),利用准则函数求解参数w 
    2、我们通过最大似然估计法定义准则函数J(w) 
    3、接下来通过最大化准则函数J(w)便可求出参数w的迭代表达式 
    4、为了更好地使用数据求出参数w,我们将第三步得到的w的迭代时向量化。自此便完成了对于参数w的推导过程,接下来便可以进行实例应用了!

    步骤一、求解准则函数J(w)

    合并(3)(4)两个式子可得: 

    这里写图片描述


    在(5)式中y={0,1},是个二分类问题,所以y只是取两个值0或是1。 
    根据(5)式可得似然函数为: 

    这里写图片描述


    对(6)式取对数有: 

    这里写图片描述


    因此定义准则函数为: 

    这里写图片描述


    最终我们的目标便是最大化似然函数,也就是最大化准则函数: 

    这里写图片描述

     


    步骤二、梯度上升算法求解参数w

    这里我们使用梯度上升算法求解参数w,因此参数w的迭代式为: 

    这里写图片描述


    其中α是正的比例因子,用于设定步长的“学习率” 
    其中对准则函数J(w)进行微分可得: 

    这里写图片描述


    所以得到最终参数w的迭代式为: 

    这里写图片描述


    上式将(1/m)去掉不影响结果,等价于下式: 

    这里写图片描述

     

    至此我们已经得出了w的迭代公式,按说是可以在引入数据的情况下进行w的计算,进而进行分类!但是数据基本都是以矩阵和向量的形式引入的,所以我们需要对上面w的迭代时进行向量化,以方便实例应用中的使用。


    步骤三、w迭代公式向量化

    首先对于引入的数据集x来说,均是以矩阵的形式引入的,如下: 

    这里写图片描述


    其中m数据的个数,n是数据的维度,也就是数据特征的数量!

     

    再者便是标签y也是以向量的形式引入的: 

    这里写图片描述


    参数w向量化为: 

    这里写图片描述


    在这里定义M=x*w,所以: 

    这里写图片描述

     

    定义上面说的sigmoid函数为: 

    这里写图片描述


    所以定义估计的误差损失为: 

    这里写图片描述


    在此基础上,可以得到步骤二中得到的参数迭代时向量化的式子为: 

    这里写图片描述

     

    至此我们便完成了参数w迭代公式的推导,下面便可以在实例中应用此迭代公式进行实际的分析了!下面我们便以简单的二分类问题为例来分析logistic回归算法的使用!!


    三、logistic回归算法的实例应用(pyhton)

    此实例便是在二维空间中给出了两类数据点,现在需要找出两类数据的分类函数,并且对于训练出的新的模型,如果输入新的数据可以判断出该数据属于二维空间中两类数据中的哪一类!

    在给出Python实现的示例代码展示之前,先介绍一下两种优化准则函数的方法: 
    1、梯度上升算法 
    2、随机梯度上升算法

    梯度上升算法: 
    梯度上升算法和我们平时用的梯度下降算法思想类似,梯度上升算法基于的思想是:要找到某个函数的最大值,最好的方法是沿着这个函数的梯度方向探寻!直到达到停止条件为止! 
    梯度上升算法的伪代码: 

    这里写图片描述

     

    随机梯度上升算法: 
    梯度上升算法在每次更新回归系数时都需要遍历整个数据集,该方法在处理小数据时还尚可,但如果有数十亿样本和成千上万的特征,那么该方法的计算复杂度太高了,改进方法便是一次仅用一个数据点来更新回归系数,此方法便称为随机梯度上升算法!由于可以在更新样本到来时对分类器进行增量式更新,因而随机梯度上升算法是一个“在线学习算法”。而梯度上升算法便是“批处理算法”!

    改进的随机梯度上升算法: 
    随机梯度上升算法虽然大大减少了计算复杂度,但是同时正确率也下降了!所以可以对随机梯度上升算法进行改进!改进分为两个方面: 
    改进一、对于学习率alpha采用非线性下降的方式使得每次都不一样 
    改进二:每次使用一个数据,但是每次随机的选取数据,选过的不在进行选择

    在知道这些信息之后下面给出示例代码,其中有详细的注释:

    #!/usr/bin/env python3
    
    # -*- coding: utf-8 -*-
    
    
    from numpy import *
    
    import matplotlib.pyplot as plt
    
    
    #从文件中加载数据:特征X,标签label
    
    def loadDataSet():
    
    dataMatrix=[]
    
    dataLabel=[]
    
    #这里给出了python 中读取文件的简便方式
    
    f=open('testSet.txt')
    
    for line in f.readlines():
    
    #print(line)
    
    lineList=line.strip().split()
    
    dataMatrix.append([1,float(lineList[0]),float(lineList[1])])
    
    dataLabel.append(int(lineList[2]))
    
    #for i in range(len(dataMatrix)):
    
    # print(dataMatrix[i])
    
    #print(dataLabel)
    
    #print(mat(dataLabel).transpose())
    
    matLabel=mat(dataLabel).transpose()
    
    return dataMatrix,matLabel
    
    
    #logistic回归使用了sigmoid函数
    
    def sigmoid(inX):
    
    return 1/(1+exp(-inX))
    
    
    #函数中涉及如何将list转化成矩阵的操作:mat()
    
    #同时还含有矩阵的转置操作:transpose()
    
    #还有list和array的shape函数
    
    #在处理矩阵乘法时,要注意的便是维数是否对应
    
    
    #graAscent函数实现了梯度上升法,隐含了复杂的数学推理
    
    #梯度上升算法,每次参数迭代时都需要遍历整个数据集
    
    def graAscent(dataMatrix,matLabel):
    
    m,n=shape(dataMatrix)
    
    matMatrix=mat(dataMatrix)
    
    
    w=ones((n,1))
    
    alpha=0.001
    
    num=500
    
    for i in range(num):
    
    error=sigmoid(matMatrix*w)-matLabel
    
    w=w-alpha*matMatrix.transpose()*error
    
    return w
    
    
    
    #随机梯度上升算法的实现,对于数据量较多的情况下计算量小,但分类效果差
    
    #每次参数迭代时通过一个数据进行运算
    
    def stocGraAscent(dataMatrix,matLabel):
    
    m,n=shape(dataMatrix)
    
    matMatrix=mat(dataMatrix)
    
    
    w=ones((n,1))
    
    alpha=0.001
    
    num=20 #这里的这个迭代次数对于分类效果影响很大,很小时分类效果很差
    
    for i in range(num):
    
    for j in range(m):
    
    error=sigmoid(matMatrix[j]*w)-matLabel[j]
    
    w=w-alpha*matMatrix[j].transpose()*error
    
    return w
    
    
    #改进后的随机梯度上升算法
    
    #从两个方面对随机梯度上升算法进行了改进,正确率确实提高了很多
    
    #改进一:对于学习率alpha采用非线性下降的方式使得每次都不一样
    
    #改进二:每次使用一个数据,但是每次随机的选取数据,选过的不在进行选择
    
    def stocGraAscent1(dataMatrix,matLabel):
    
    m,n=shape(dataMatrix)
    
    matMatrix=mat(dataMatrix)
    
    
    w=ones((n,1))
    
    num=200 #这里的这个迭代次数对于分类效果影响很大,很小时分类效果很差
    
    setIndex=set([])
    
    for i in range(num):
    
    for j in range(m):
    
    alpha=4/(1+i+j)+0.01
    
    
    dataIndex=random.randint(0,100)
    
    while dataIndex in setIndex:
    
    setIndex.add(dataIndex)
    
    dataIndex=random.randint(0,100)
    
    error=sigmoid(matMatrix[dataIndex]*w)-matLabel[dataIndex]
    
    w=w-alpha*matMatrix[dataIndex].transpose()*error
    
    return w
    
    
    #绘制图像
    
    def draw(weight):
    
    x0List=[];y0List=[];
    
    x1List=[];y1List=[];
    
    f=open('testSet.txt','r')
    
    for line in f.readlines():
    
    lineList=line.strip().split()
    
    if lineList[2]=='0':
    
    x0List.append(float(lineList[0]))
    
    y0List.append(float(lineList[1]))
    
    else:
    
    x1List.append(float(lineList[0]))
    
    y1List.append(float(lineList[1]))
    
    
    fig=plt.figure()
    
    ax=fig.add_subplot(111)
    
    ax.scatter(x0List,y0List,s=10,c='red')
    
    ax.scatter(x1List,y1List,s=10,c='green')
    
    
    xList=[];yList=[]
    
    x=arange(-3,3,0.1)
    
    for i in arange(len(x)):
    
    xList.append(x[i])
    
    
    y=(-weight[0]-weight[1]*x)/weight[2]
    
    for j in arange(y.shape[1]):
    
    yList.append(y[0,j])
    
    
    ax.plot(xList,yList)
    
    plt.xlabel('x1');plt.ylabel('x2')
    
    plt.show()
    
    
    
    if __name__ == '__main__':
    
    dataMatrix,matLabel=loadDataSet()
    
    #weight=graAscent(dataMatrix,matLabel)
    
    weight=stocGraAscent1(dataMatrix,matLabel)
    
    print(weight)
    
    draw(weight)

    上面程序运行结果为: 
    这里写图片描述

    其中: 
    图(1)是使用梯度上升算法的结果,运算复杂度高; 
    图(2)是使用随机梯度上升算法,分类效果略差吗,运算复杂度低; 
    图(3)是使用改进后的随机梯度上升算法,分类效果好,运算复杂度低。

    上述程序数据连接,提取密码为:1l1s

    文中如有何问题,欢迎指正,谢谢!!!

    参考文献:

    https://blog.csdn.net/feilong_csdn/article/details/64128443

    展开全文
  • · 代码目的:利用手写、sklearn两种感知机模型,对鸢尾花数据集进行二分类 作者:CSDN 征途黯然.    一、鸢尾花(iris)数据集   Iris 鸢尾花数据集是一个经典数据集,在统计学习和机器学习领域都经常被用作示例...
  • from keras.utils.np_utils import to_categorical注意:当使用categorical_crossentropy损失函数时,你的标签应为类模式,例如如果你有10个类别,每一个样本的标签应该是一个10维的向量,该向量在对应有值的索引...
  • 转自个人微信公众号【Memo_Cleon】的统计学习笔记两个概念:RR和OR二分类资料的logistic回归SPSS操作示例几个需要注意的问题:样本量、哑变量、模型拟合效果和拟合优度检验、多重共线【1】两个概念RR(Relative Risk)...
  • [n,1]范围为[0,1] # 将概率转化为预测的类别 def binary(self, y): y = y > 0.5 return y.astype(int) # 二分类sigmoid函数 def sigmoid(self, x): return 1/(1 + np.exp(-x)) # 二分类交叉熵损失 def cross_entropy...
  • 严格意义上讲XGBoost并不是一种模型,而是一个可供用户轻松解决分类、回归或排序问题的软件包。它内部实现了梯度提升树(GBDT)模型,并对模型中的算法进行了诸多优化,在取得高精度的同时又保持了极快的速度,在一段...
  • DL4J实战之:鸢尾花分类

    千次阅读 2021-06-14 15:41:47
    通过经典的鸢尾花分类,第一体验DL4J开发
  • 二分类分类、标签 图像分类原理与挑战 快速上手卷积神经网络LeNet-5 应用:万能公式 ① 问题定义:图像分类,使用LeNet-5网络完成手写数字识别图片的分类。 ② 数据准备:继续应用框架中封装好的手写...
  • 对于大数据的非线性分类,可以使用 fitckernel 训练类高斯核分类模型。
  • 机器学习:多分类

    2021-11-17 17:40:45
    对于分类问题,二分类分类方法则无法进行判断,因此我们定义评分函数进行判断。 在类设置中,根据评分函数定义假设:。与点 关联的标签是导致最大分数 的标签,该分数定义了以下映射: 到 : 其中,其中每个...
  • MATLAB实现SVM二分类 SVM是名噪一时的机器学习方法,自20世纪末 以来在模式识别领域风生水起,至今仍然活跃在各大论文期刊中。无论是和其他特征提取方法的结合,还是和其他模式识别方法的对比,SVM的表现都可圈可点...
  • CREATE TABLE t_category(ID INT IDENTITY(1,1) PRIMARY KEY,Name VARCHAR(40) NOT NULL,ParentID INT DEFAULT(-1))?-- 插入一些测试数据INSERT INTO t_category(name) VALUES('计算机类')INSERT INTO t_category...
  • 问题描述: 使用sklearn的brier_score_loss类计算四分类...新版sklearn的brier_score_loss不支持多分类了 解决方案: 先对测试集的标签进行哑变量变换: proba= models.predict_proba(Xtest) Ytest_= Ytest.copy() Yte
  • NOTEBOOK支持向量机(分类问题公式及python实现)此notebook包括:1、支持向量机介绍2、什么是线性可分类支持向量机3、什么是线性分类支持向量机4、硬间隔化和软间隔化5、什么是线性分类支持向量机的对偶形式6、非线性...
  • 混淆矩阵:用于多分类模型评估(pytorch)

    千次阅读 多人点赞 2021-03-25 14:58:11
    这里写目录标题1. 混淆矩阵介绍级目录三级目录2. 代码实现 1. 混淆矩阵介绍 级目录 三级目录 2. 代码实现
  • shopify二次开发及目录详解

    千次阅读 2021-01-09 11:50:48
    公司需求要求对shopify的官网要进行二次开发,可以创建新的模块,再此我也一脸懵,点进去发现他的开发对习惯了前后端分离和模块化开发的人来说简直是折磨。整个官网的样式都在一个文件下,但是没办法需求来了还是要...
  • 邮件分类消歧过程 在第阶段我们主要进行优化过程,包括邮件消歧和结果优化,这里包括邮件火星文字“城人”“出兽”等,同时解决ByPass问题,这些火星文字实际上是一种对抗文本,可以尝试word2vec来识别,比如与它...
  • 深度学习入门篇,简单的实例讲明白图像分类

    千次阅读 多人点赞 2021-10-28 19:15:17
    使用 Keras 训练您的第一个简单神经网络不需要很代码,但我们将开始缓慢,一步一步地进行,确保您了解如何在自己的自定义数据集中培训网络的过程。 我们今天将涵盖的步骤包括: 安装 Keras 和其他对系统的依赖 从...
  • 蓝旭后端第六培训课 MySQL()

    千次阅读 2021-05-18 18:32:46
    蓝旭后端第六培训课 MySQL()命令行操作MySQL登录访问使用切换至你想操作的数据库显示当前数据库的所有数据库表退出数据库最后补充SQL语句终于来咯SQL语句入门SQL语句分为五个部分数据查询语句 DQL数据操作语句...
  • 对一个值或成组的值进行重分类的方法是:使用替代字段;基于某条件,如指定的间隔(如按照10个间隔将值分组);按区域重分类(如将值分成10个所含像元数量保持不变的组)。这些工具可将输入栅格中的众多值轻松地更改...
  • 适用于超小规模数据集的分类

    千次阅读 多人点赞 2021-04-13 10:17:59
    文章目录1. 背景1.1 研究方法1.2 数据集和代码链接2. 测试结果3. 关于数据独立同分布的思考4. 结论5....1. 背景 1.1 研究方法   随着深度学习如火如荼的发展,对大数据的训练和...获取大量用于分类的小型基准数据集,总
  • 空气质量预报二次建模 大气污染系指由于人类活动或自然过程引起某些物质进入大气中,呈现足够的浓度,达到了足够的时间,并因此危害了人体的舒适、健康和福利或危害了生态环境[1]。污染防治实践表明,建立空气质量...
  • 与线性判别分析类似,二次判别分析是另外一种线性判别分析算法,二者拥有类似的算法特征,区别仅在于:当不同分类样本的协方差矩阵相同时,使用线性判别分析;当不同分类样本的协方差矩阵不同时,则应该使用二次判别...
  • SENet实战详解:使用SE-ReSNet50实现对植物幼苗的分类

    千次阅读 多人点赞 2021-10-21 18:49:12
    摘要 1、SENet概述 ​ Squeeze-and-Excitation Networks(简称 SENet)是 Momenta 胡杰团队(WMW)提出的新的...作者在文中将SENet block插入到现有的多种分类网络中,都取得了不错的效果。作者的动机是希望显式地建模
  • 理解证券行业“行业分类

    千次阅读 2021-04-24 14:50:49
    经常看到各种行业分类,申万行业、wind行业、中信行业等等,总是迷迷糊糊的。 关于“分类”的分类,一般有两种: 管理型(国民经济行业分类) 用于行政管理; ISIC(International Standard Industrial ...
  • 图像分类halcon

    千次阅读 2021-11-14 20:12:13
    分类器的分类: (1)基于神经网络,特别是多层感知器的MLP分类器 (2)基于支持向量机的SVM分类器 (3)基于高斯混合模型的GMM分类器 (4)基于k近邻的k-NN分类器 图像分类的一般流程: (1)准备一组...
  • “花朵分类“ 手把手搭建【卷积神经网络】

    千次阅读 多人点赞 2021-05-09 17:01:58
    本文介绍卷积神经网络的入门案例,通过搭建和训练一个模型,来对几种常见的花朵进行识别分类;使用到TF的花朵数据集,它包含5类,即:“雏菊”,“蒲公英”,“玫瑰”,“向日葵”,“郁金香”;共 3670张彩色图片;...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 535,058
精华内容 214,023
关键字:

多次二分类