Knowledge
正则化(或者称为惩罚项)
一般而言,正则化的通项为$$w^* = arg min \sum_i L(y_i, f(x_i;w))+ \lambda \Omega(w)$$
规则化函数Ω(w)也有很多种选择,一般是模型复杂度的单调递增函数,模型越复杂,规则化值就越大。比如,规则化项可以是模型参数向量的范数。然而,不同的选择对参数w的约束不同,取得的效果也不同,但我们在论文中常见的都聚集在:零范数、一范数、二范数、迹范数、Frobenius范数和核范数等等。
常见的优化是使用的L1与L2范数,这是为什么呢? ——> 因为这本质其实简化到了一个凸优化问题,凸优化问题是有解的,所以常见的就是L1和L2范数
参考文章
1 2 3 4 5 6 https://blog.csdn.net/zouxy09/article/details/24971995?ADUIN=189151916&ADSESSION=1451702742&ADTAG=CLIENT.QQ.5449_.0&ADPUBNO=26525 https://www.zhihu.com/question/38081976 【“L1和L2正则化”直观理解(之一),从拉格朗日乘数法角度进行理解-哔哩哔哩】 https://b23.tv/hzgdwPP
正则化的种类
参数范数惩罚
L0正则化 与 L1 正则化
L0范数是指向量中非0的元素的个数。如果我们用L0范数来规则化一个参数矩阵W的话,就是希望W的大部分元素都是0。
L1正则化:也称为 Lasso 正则化,它通过在模型的损失函数中增加权重的 L1 范数(权重向量的绝对值之和)来实现正则化。L1 正则化倾向于产生稀疏权重矩阵,即将一些权重推向零,从而实现特征选择的效果。
L1的损失函数为:
L L 1 = L d a t a + λ ∑ i = 1 n ∣ ∣ w i ∣ ∣ 1 L_{L1} = L_{data} + \lambda \sum_{i=1}^n||w_i||_1
L L 1 = L d a t a + λ i = 1 ∑ n ∣ ∣ w i ∣ ∣ 1
为啥我们常见的只有L1范数进行约束而不是使用L0范数进行约束,原因其实在上面已经说过
一是因为L0范数很难优化求解(NP难问题)。
二是L1范数是L0范数的最优凸近似,而且它比L0范数要容易优化求解。所以大家才把目光和万千宠爱转于L1范数。
总之一句话 L1范数和L0范数都可以实现稀疏,L1因具有比L0更好的优化求解特性而被广泛应用。
稀疏化的优点
1)特征选择(Feature Selection):
大家对稀疏规则化趋之若鹜的一个关键原因在于它能实现特征的自动选择。一般来说,xi的大部分元素(也就是特征)都是和最终的输出yi没有关系或者不提供任何信息的,在最小化目标函数的时候考虑xi这些额外的特征,虽然可以获得更小的训练误差,但在预测新的样本时,这些没用的信息反而会被考虑,从而干扰了对正确yi的预测。稀疏规则化算子的引入就是为了完成特征自动选择的光荣使命,它会学习地去掉这些没有信息的特征,也就是把这些特征对应的权重置为0。
2)可解释性(Interpretability):
另一个青睐于稀疏的理由是,模型更容易解释。例如患某种病的概率是y,然后我们收集到的数据x是1000维的,也就是我们需要寻找这1000种因素到底是怎么影响患上这种病的概率的。假设我们这个是个回归模型:y=w1x1+w2 x2+…+w1000x1000+b(当然了,为了让y限定在[0,1]的范围,一般还得加个Logistic函数)。通过学习,如果最后学习到的w 就只有很少的非零元素,例如只有5个非零的wi,那么我们就有理由相信,这些对应的特征在患病分析上面提供的信息是巨大的,决策性的。也就是说,患不患这种病只和这5个因素有关,那医生就好分析多了。但如果1000个wi都非0,医生面对这1000种因素,累觉不爱。
L2正则化
L2 正则化 :也称为 Ridge 正则化,它通过在模型的损失函数中增加权重的 L2 范数(权重向量的平方和)来实现正则化。L2 正则化会使权重值变得较小,但不会直接导致权重稀疏,因此不具有特征选择的作用,但可以有效地控制模型的复杂度。
L2的损失函数为:
L L 1 = L d a t a + λ ∑ i = 1 n ∣ ∣ w i ∣ ∣ 2 2 L_{L1} = L_{data} + \lambda \sum_{i=1}^n||w_i||_2^2
L L 1 = L d a t a + λ i = 1 ∑ n ∣ ∣ w i ∣ ∣ 2 2
实例
Elastic Net 正则化
1 A correction has been published: _Journal of the Royal Statistical Society Series B: Statistical Methodology_, Volume 67, Issue 5, November 2005, Page 768, [https://doi.org/10.1111/j.1467-9868.2005.00527.x](https://doi.org/10.1111/j.1467-9868.2005.00527.x)
Elastic Net 正则化 :Elastic Net 是 L1 和 L2 正则化的组合,它在损失函数中同时使用 L1 和 L2 范数,可以综合两者的优点。即吸收了L1对参数的稀疏化,同时又吸收了L2对参数的放缩的特点。
因此其损失函数为二者惩罚项的组合:
L L 1 = L d a t a + λ 1 ∑ i = 1 n ∣ ∣ w i ∣ ∣ 1 + λ 2 ∑ i = 1 n ∣ ∣ w i ∣ ∣ 2 2 L_{L1} = L_{data} + \lambda_1 \sum_{i=1}^n||w_i||_1 + \lambda_2 \sum_{i=1}^n||w_i||_2^2
L L 1 = L d a t a + λ 1 i = 1 ∑ n ∣ ∣ w i ∣ ∣ 1 + λ 2 i = 1 ∑ n ∣ ∣ w i ∣ ∣ 2 2
Elastic Net优点
平衡L1和L2 :通过调整( λ 1 \lambda_1 λ 1 )和( λ 2 \lambda_2 λ 2 )的值,可以在L1和L2正则化之间进行权衡,以适应不同的数据特性。
特征选择 :当( λ 1 \lambda_1 λ 1 )较大时,弹性网倾向于进行特征选择,将不重要的特征权重置为零。
稳定性 :当( λ 2 \lambda_2 λ 2 )较大时,弹性网倾向于保持权重较小,增加模型的稳定性。
Dropout
最大范数约束
注入噪声
在这个方法中,我们在反向传播对学习的权重进行更新的过程中,少量随机噪声被添加到更新后的权重中,以使其更鲁棒或对微小变化不敏感,这有助于模型构建更稳健的特征集,从而确保模型不会过度拟合训练数据。然而,作为正则化方式之一,这种方法并没有取得很好的效果。
提前停止
数据增强
几何变换类:翻转、旋转、缩放、裁剪、移位
颜色变换类:高斯噪声、模糊、颜色变换、擦除、填充等
多样本数据增强等高级增强方法
Homework
9.26
问题
用 matlab 或者 python 实现一个前馈网络,完成分类任务,只是选择一个分类评估指标结果。提交源码和实验结果。
解答
解释
借助识别手写数字的数据集,在 20 轮的训练后进行评估,借助 sklearn 的机器学习库,计算了准确率,精准率,F1指数,召回率以及混淆矩阵 的值。
源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 import torchfrom torchvision import datasets, transformsfrom torch.utils.data import DataLoaderimport torch.nn.functional as Ffrom sklearn.metrics import accuracy_score, classification_report, confusion_matrix, precision_score, recall_score, f1_scoreimport torch.optim as optimbatch_size = 64 transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.1307 ,), (0.3081 ,))]) train_dataset = datasets.MNIST(root='../dataset/mnist/' , train=True , download=True , transform=transform) train_loader = DataLoader(train_dataset, shuffle=True , batch_size=batch_size) test_dataset = datasets.MNIST(root='../dataset/mnist/' , train=False , download=True , transform=transform) test_loader = DataLoader(test_dataset, shuffle=False , batch_size=batch_size) class NET (torch.nn.Module): def __init__ (self ): super (NET, self ).__init__() self .n1 = torch.nn.Linear(784 , 512 ) self .n2 = torch.nn.Linear(512 , 256 ) self .n3 = torch.nn.Linear(256 , 128 ) self .n4 = torch.nn.Linear(128 , 64 ) self .n5 = torch.nn.Linear(64 , 10 ) def forward (self, x ): x = x.view(-1 , 784 ) x = F.relu(self .n1(x)) x = F.relu(self .n2(x)) x = F.relu(self .n3(x)) x = F.relu(self .n4(x)) return self .n5(x) device = torch.device("cuda" if torch.cuda.is_available() else "cpu" ) model = NET().to(device) criterion = torch.nn.CrossEntropyLoss() optimization = torch.optim.SGD(model.parameters(), lr=0.01 , momentum=0.9 ) def train (epoch ): model.train() running_loss = 0.0 for batch_index, data in enumerate (train_loader, 0 ): inputs, labels = data inputs, labels = inputs.to(device), labels.to(device) optimization.zero_grad() output = model(inputs) loss = criterion(output, labels) loss.backward() optimization.step() running_loss += loss.item() if batch_index % 300 == 299 : print ('[%d, %d] loss = %f' % (epoch + 1 , batch_index + 1 , running_loss / 300 )) running_loss = 0.0 def test (): model.eval () correct = 0 total = 0 all_labels = [] all_preds = [] with torch.no_grad(): for data in test_loader: inputs, labels = data inputs, labels = inputs.to(device), labels.to(device) outputs = model(inputs) _, predicted = torch.max (outputs.data, 1 ) all_labels.extend(labels.cpu().numpy()) all_preds.extend(predicted.cpu().numpy()) total += labels.size(0 ) correct += (predicted == labels).sum ().item() accuracy = accuracy_score(all_labels, all_preds) print ('Accuracy is %f%%' % (accuracy * 100 )) precision = precision_score(all_labels, all_preds, average='weighted' ) recall = recall_score(all_labels, all_preds, average='weighted' ) f1 = f1_score(all_labels, all_preds, average='weighted' ) print ('Precision is %f%%' % (precision * 100 )) print ('Recall is %f%%' % (recall * 100 )) print ('F1 is %f%%' % (f1 * 100 )) confu_matr = confusion_matrix(all_labels, all_preds) print ('Confusion Matrix is \n' , confu_matr) if __name__ == '__main__' : for epoch in range (20 ): train(epoch) print ('=====Finished Training=====' ) test()
实验结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 Accuracy is 98.410000% Precision is 98.410806% Recall is 98.410000% F1 is 98.410144% Confusion Matrix is [[ 970 0 2 0 0 2 2 0 2 2] [ 0 1128 1 1 0 1 2 0 2 0] [ 3 1 1013 3 2 0 2 2 4 2] [ 0 0 2 992 0 4 0 4 4 4] [ 1 0 4 0 963 0 3 2 0 9] [ 2 0 0 5 1 877 1 1 2 3] [ 2 2 1 0 3 2 947 0 1 0] [ 0 2 8 0 0 0 0 1011 3 4] [ 0 1 3 5 1 1 2 3 953 5] [ 4 2 0 1 8 4 1 2 0 987]]