Skip to content

Latest commit

 

History

History
919 lines (625 loc) · 45.3 KB

西瓜书带学训练营·实战任务.md

File metadata and controls

919 lines (625 loc) · 45.3 KB

目录

西瓜书带学训练营·实战任务

西瓜书带学训练营·实战任务

1. “达观杯”文本智能处理挑战赛:sklearn包中logistic算法的使用 目录

1.1. 任务描述 目录

具体任务可以到 '达观杯'文本智能处理挑战赛官网 查看

任务:建立模型通过长文本数据正文(article),预测文本对应的类别(class)

数据:

数据包含2个csv文件:

  • train_set.csv

    此数据集用于训练模型,每一行对应一篇文章。文章分别在“字”和“词”的级别上做了脱敏处理。共有四列:

    第一列是文章的索引(id),第二列是文章正文在“字”级别上的表示,即字符相隔正文(article);第三列是在“词”级别上的表示,即词语相隔正文(word_seg);第四列是这篇文章的标注(class)。

    注:每一个数字对应一个“字”,或“词”,或“标点符号”。“字”的编号与“词”的编号是独立的!

  • test_set.csv

    此数据用于测试。数据格式同train_set.csv,但不包含class

    注:test_set与train_test中文章id的编号是独立的。

1.2. 编程实现 目录

使用logistic回归来实现这个多元分类任务

import pandas as pd
from sklearn.feature_extract.txt import TfidfVectorizer
from sklearn.decomposition import TruncatedSVD
from sklearn.linear_model import LogisticRegression
from sklearn.model_select import train_test_split
from sklearn.externals import joblib
import time

t_start = time.time()

# ===========================================================
# 1. 载人数据与数据预处理
df_train = pd.read_csv('data/train_set.csv')
df_train = df_train.drop(columns='article',inplace=True)
df_test = pd.read_csv('data/test_set.csv')
df_test = df_test.drop(columns='article',inplace=True)
y_train = (df_train['class'] - 1).values


# ===========================================================
# 2. 特征工程,这里先使用经典的文本特征提取方法TFIDF,提取的TFIDF特征
vectorizer = TfidfVectorizer(ngram_range=(1, 2), min_df=3, max_df=0.9, sublinear_tf=True)
vectorizer.fit(df_train['word_seg'])
X_train = vectorizer.transform(df_train['word_seg'])
X_test = vectorizer.transform(df_test['word_seg'])

# 可以将得到的TFIDF特征保存至本地
'''
data = (X_train,y_train,X_test)
f = open('data/data_tfidf.pkl','wb')
pickle.dump(data,f)
f.close()
'''


# ===========================================================
# 3. 特征降维,将上一步提取的TFIDF特征使用lsa方法进行特征降维
lsa = TruncatedSVD(n_components=200)
X_train = lsa.transform(X_train)
X_test = lsa.transform(X_test)


# ===========================================================
# 4. 训练分类器

# 划分训练集和验证集
X_train,X_vali,y_train,y_vali = train_test_split(X_train,y_train,test_size=0.1,random_state=0)

##  multi_class:分类方式选择参数,有"ovr(默认)"和"multinomial"两个值可选择,在二元逻辑回归中无区别
##  solver:优化算法选择参数,当penalty为"l1"时,参数只能是"liblinear(坐标轴下降法)";"lbfgs"和"cg"都是关于目标函数的二阶泰勒展开
##  当penalty为"l2"时,参数可以是"lbfgs(拟牛顿法)","newton_cg(牛顿法变种)","seg(minibactch随机平均梯度下降)"
lr = LogisticRegression(multi_class="ovr",penalty="l2",solver="lbfgs")
lr.fit(X_train,y_train)

# 模型的保存与持久化
joblib.dump(lr,"logistic_lr.model")
joblib.load("logistic_lr.model") #加载模型,会保存该model文件


# ===========================================================
# 5. 在验证集上评估模型
pre_vali = lr.predict(X_vali)
pre_score = f1_score(y_true=y_vali,y_pred=pre_vali,average='macro')
print("验证集分数:{}".format(score_vali))


# ===========================================================
# 6. 对测试集进行预测
y_test = lr.predict(X_test) + 1

1.3. sklearn包中logistic算法的使用 目录

2. 鸢尾花数据分类:sklearn包中决策树算法类库的使用 目录

2.1. DecisionTreeClassifier实例 目录

from itertools import product

import numpy as np
import matplotlib.pyplot as plt

from sklearn import datasets
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import MinMaxScaler
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2
from sklearn.decomposition import PCA


# 使用自带的iris数据
iris = datasets.load_iris()
X = iris.data[:, np.arange(0,4)]
y = iris.target

# 划分训练集与测试集
x_train, x_test, y_train, y_test = train_test_split(X,y,test_size=0.2,random_state=14)
print("训练数据集样本总数:%d;测试数据集样本总数:%d" %(x_train.shape[0],x_test.shape[0]))

# 对数据集进行标准化
ss = MinMaxScaler()
x_train = ss.fit_transform(x_train,y_train)
x_test = ss.transform(x_test)

# 特征选择:从已有的特征属性中选择出影响目标最大的特征属性
# 常用方法:
#	离散属性:F统计量、卡方系数、互信息mutual_info_classif
#	连续属性:皮尔逊相关系数、F统计量、互信息mutual_info_classif}
# 这里使用离散属性的卡方系数,实现函数为SelectKBest,用SelectKBest方法从四个原始特征属性中选择出最能影响目标的3个特征属性
ch2 = SelectKBest(chi2,k=3) # k默认为10,指定后会返回想要的特征个数
ch2.fit(x_train,y_train)
x_train = ch2.transform(x_train)
x_test = ch2.transform(x_test)

# 特征降维,这里使用PCA方法
pca = PCA(n_components=2)   # 构建一个PCA对象,设置最终维度为2维。这里为了后边画图方便,将数据维度设置为 2,一般用默认不设置就可以
x_train = pca.fit_transform(x_train) # 训练与转换,也可以拆分成两步
x_test = pca.transform(x_test)

# 训练模型
#	criterion:指定特征选择标准,可以使用"gini"或者"entropy",前者代表基尼系数,后者代表信息增益
#	max_depth:限制树的最大深度4
clf = DecisionTreeClassifier(criterion="entropy",max_depth=4)
clf.fit(X, y) # 拟合模型


# 画图
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
# 生成网格采样点
xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.1),
                     np.arange(y_min, y_max, 0.1))

Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)

plt.contourf(xx, yy, Z, alpha=0.4)
plt.scatter(X[:, 0], X[:, 1], c=y, alpha=0.8)
plt.show()

2.2. 可视化决策树 目录

scikit-learn中决策树的可视化一般需要安装graphviz,主要包括graphviz的安装和python的graphviz插件的安装

    1. 安装graphviz。下载地址在:http://www.graphviz.org/。如果你是linux,可以用apt-get或者yum的方法安装。如果是windows,就在官网下载msi文件安装。无论是linux还是windows,装完后都要设置环境变量,将graphviz的bin目录加到PATH,比如我是windows,将C:/Program Files (x86)/Graphviz2.38/bin/加入了PATH
    1. 安装python插件graphviz: pip install graphviz
    1. 安装python插件pydotplus: pip install pydotplus

这样环境就搭好了,有时候python会很笨,仍然找不到graphviz,这时,可以在代码里面加入这一行:

os.environ["PATH"] += os.pathsep + 'C:/Program Files (x86)/Graphviz2.38/bin/'

可视化决策树的代码:

from IPython.display import Image  
from sklearn import tree
import pydotplus 
dot_data = tree.export_graphviz(clf, out_file=None, 
                         feature_names=iris.feature_names,  
                         class_names=iris.target_names,  
                         filled=True, rounded=True,  
                         special_characters=True)  
graph = pydotplus.graph_from_dot_data(dot_data)  
Image(graph.create_png())

3. sklearn中随机测试数据:sklearn包中SVM算法库的使用 目录

3.1. SVM相关知识点回顾 目录

3.1.1. SVM与SVR 目录

  • SVM分类算法

    其原始形式是:

    其中m为样本个数,我们的样本为(x1,y1),(x2,y2),...,(xm,ym)。w,b是我们的分离超平面的w∙ϕ(xi)+b=0系数, ξi为第i个样本的松弛系数, C为惩罚系数。ϕ(xi)为低维到高维的映射函数

    通过拉格朗日函数以及对偶化后的形式为:

  • SVR回归算法

    其中m为样本个数,我们的样本为(x1,y1),(x2,y2),...,(xm,ym)。w,b是我们的回归超平面的w∙xi+b=0系数, ξi,ξi为第i个样本的松弛系数, C为惩罚系数,ϵ为损失边界,到超平面距离小于ϵ的训练集的点没有损失。ϕ(xi)为低维到高维的映射函数。

3.1.2. 核函数 目录

在scikit-learn中,内置的核函数一共有4种:

  • 线性核函数(Linear Kernel)表达式为:K(x,z)=x∙z,就是普通的内积

  • 多项式核函数(Polynomial Kernel)是线性不可分SVM常用的核函数之一,表达式为:K(x,z)=(γx∙z+r)d ,其中,γ,r,d都需要自己调参定义

  • 高斯核函数(Gaussian Kernel),在SVM中也称为径向基核函数(Radial Basis Function,RBF),它是 libsvm 默认的核函数,当然也是 scikit-learn 默认的核函数。表达式为:K(x,z)=exp(−γ||x−z||2), 其中,γ大于0,需要自己调参定义

  • Sigmoid核函数(Sigmoid Kernel)也是线性不可分SVM常用的核函数之一,表达式为:K(x,z)=tanh(γx∙z+r), 其中,γ,r都需要自己调参定义

一般情况下,对非线性数据使用默认的高斯核函数会有比较好的效果,如果你不是SVM调参高手的话,建议使用高斯核来做数据分析。 

3.2. sklearn中SVM相关库的简介 目录

scikit-learn SVM算法库封装了libsvm 和 liblinear 的实现,仅仅重写了算法了接口部分

3.2.1. 分类库与回归库 目录

  • 分类算法库

    包括SVC, NuSVC,和LinearSVC 3个类

    对于SVC, NuSVC,和LinearSVC 3个分类的类,SVC和 NuSVC差不多,区别仅仅在于对损失的度量方式不同,而LinearSVC从名字就可以看出,他是线性分类,也就是不支持各种低维到高维的核函数,仅仅支持线性核函数,对线性不可分的数据不能使用

  • 回归算法库

    包括SVR, NuSVR,和LinearSVR 3个类

    同样的,对于SVR, NuSVR,和LinearSVR 3个回归的类, SVR和NuSVR差不多,区别也仅仅在于对损失的度量方式不同。LinearSVR是线性回归,只能使用线性核函数

3.2.2. 高斯核调参 目录

3.2.2.1. 需要调节的参数 目录

  • SVM分类模型

    如果是SVM分类模型,这两个超参数分别是惩罚系数CRBF核函数的系数γ

    惩罚系数C

    它在优化函数里主要是平衡支持向量的复杂度和误分类率这两者之间的关系,可以理解为正则化系数

    • 当C比较大时,我们的损失函数也会越大,这意味着我们不愿意放弃比较远的离群点。这样我们会有更加多的支持向量,也就是说支持向量和超平面的模型也会变得越复杂,也容易过拟合

    • 当C比较小时,意味我们不想理那些离群点,会选择较少的样本来做支持向量,最终的支持向量和超平面的模型也会简单

    scikit-learn中默认值是1

    C越大,泛化能力越差,易出现过拟合现象;C越小,泛化能力越好,易出现过欠拟合现象

    BF核函数的参数γ

    RBF 核函数K(x,z)=exp(−γ||x−z||2) γ>0

    γ主要定义了单个样本对整个分类超平面的影响

    • 当γ比较小时,单个样本对整个分类超平面的影响比较小,不容易被选择为支持向量

    • 当γ比较大时,单个样本对整个分类超平面的影响比较大,更容易被选择为支持向量,或者说整个模型的支持向量也会多

    scikit-learn中默认值是 1/样本特征数

    γ越大,训练集拟合越好,泛化能力越差,易出现过拟合现象

    如果把惩罚系数C和RBF核函数的系数γ一起看,当C比较大, γ比较大时,我们会有更多的支持向量,我们的模型会比较复杂,容易过拟合一些。如果C比较小 , γ比较小时,模型会变得简单,支持向量的个数会少

  • SVM回归模型

    SVM回归模型的RBF核比分类模型要复杂一点,因为此时我们除了惩罚系数C和RBF核函数的系数γ之外,还多了一个损失距离度量ϵ

    对于损失距离度量ϵ,它决定了样本点到超平面的距离损失

    • 当 ϵ 比较大时,损失较小,更多的点在损失距离范围之内,而没有损失,模型较简单

    • 当 ϵ 比较小时,损失函数会较大,模型也会变得复杂

    scikit-learn中默认值是0.1

    如果把惩罚系数C,RBF核函数的系数γ和损失距离度量ϵ一起看,当C比较大, γ比较大,ϵ比较小时,我们会有更多的支持向量,我们的模型会比较复杂,容易过拟合一些。如果C比较小 , γ比较小,ϵ比较大时,模型会变得简单,支持向量的个数会少

3.2.2.2. 调参方法:网格搜索 目录

对于SVM的RBF核,我们主要的调参方法都是交叉验证。具体在scikit-learn中,主要是使用网格搜索,即GridSearchCV类

from sklearn.model_selection import GridSearchCV
grid = GridSearchCV(SVC(), param_grid={"C":[0.1, 1, 10], "gamma": [1, 0.1, 0.01]}, cv=4)
grid.fit(X, y)

将GridSearchCV类用于SVM RBF调参时要注意的参数有:

  1. estimator:即我们的模型,此处我们就是带高斯核的SVC或者SVR

  2. param_grid:即我们要调参的参数列表。 比如我们用SVC分类模型的话,那么param_grid可以定义为{"C":[0.1, 1, 10], "gamma": [0.1, 0.2, 0.3]},这样我们就会有9种超参数的组合来进行网格搜索,选择一个拟合分数最好的超平面系数

  3. cv:S折交叉验证的折数,即将训练集分成多少份来进行交叉验证。默认是3。如果样本较多的话,可以适度增大cv的值

3.3. 编程实现 目录

  1. 生成测试数据

    from sklearn.datasets import make_circles
    from sklearn.preprocessing import StandardScaler
    
    # 生成一些随机数据用于后续分类
    X, y = make_circles(noise=0.2, factor=0.5, random_state=1) # 生成时加入了一些噪声
    X = StandardScaler().fit_transform(X) # 把数据归一化
    
    

    生成的随机数据可视化结果如下:

  2. 调参

    接着采用网格搜索的策略进行RBF核函数参数搜索

    from sklearn.model_selection import GridSearchCV
    grid = GridSearchCV(SVC(), param_grid={"C":[0.1, 1, 10], "gamma": [1, 0.1, 0.01]}, cv=4) # 总共有9种参数组合的搜索空间
    grid.fit(X, y)
    print("The best parameters are %s with a score of %0.2f"
          % (grid.best_params_, grid.best_score_))
    
    输出为:
    The best parameters are {'C': 10, 'gamma': 0.1} with a score of 0.91
    

    可以对9种参数组合训练的结果进行可视化,观察分类的效果:

    x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
    y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
    xx, yy = np.meshgrid(np.arange(x_min, x_max,0.02),
                         np.arange(y_min, y_max, 0.02))
    
    for i, C in enumerate((0.1, 1, 10)):
        for j, gamma in enumerate((1, 0.1, 0.01)):
            plt.subplot()       
            clf = SVC(C=C, gamma=gamma)
            clf.fit(X,y)
            Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])
    
            # Put the result into a color plot
            Z = Z.reshape(xx.shape)
            plt.contourf(xx, yy, Z, cmap=plt.cm.coolwarm, alpha=0.8)
    
            # Plot also the training points
            plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.coolwarm)
    
            plt.xlim(xx.min(), xx.max())
            plt.ylim(yy.min(), yy.max())
            plt.xticks(())
            plt.yticks(())
            plt.xlabel(" gamma=" + str(gamma) + " C=" + str(C))
            plt.show()
    
C \ gamma 1 0.1 0.001
0.1
1
10

4.sklearn包中朴素贝叶斯库的使用 目录

4.1. 朴素贝叶斯相关知识点回顾 目录

4.1.1. 什么是朴素贝叶斯分类器 目录

判别式模型(discriminative models):像决策树、BP神经网络、支持向量机等,都可以归入判别式模型,它们都是直接学习出输出Y与特征X的关系,如:

  • 决策函数 Y=f(X)
  • 条件概率 P(Y|X)

生成式模型 (gernerative models):先对联合概率分布 P(X,Y) 进行建模,然后再由此获得P(Y|X) = P(X,Y)/P(X)

贝叶斯学派的思想:

贝叶斯学派的思想可以概括为先验概率+数据=后验概率。也就是说我们在实际问题中需要得到的后验概率,可以通过先验概率和数据一起综合得到。数据大家好理解,被频率学派攻击的是先验概率,一般来说先验概率就是我们对于数据所在领域的历史经验,但是这个经验常常难以量化或者模型化,于是贝叶斯学派大胆的假设先验分布的模型,比如正态分布,beta分布等。这个假设一般没有特定的依据,因此一直被频率学派认为很荒谬。虽然难以从严密的数学逻辑里推出贝叶斯学派的逻辑,但是在很多实际应用中,贝叶斯理论很好用,比如垃圾邮件分类,文本分类

如何对P(X,Y)进行建模?

假如我们的分类模型样本是:

(x(1)1,x(1)2,...x(1)n,y1), (x(2)1,x(2)2,...x(2)n,y2),...(x(m)1,x(m)2, ..., x(m)n,ym)

P(X, Y) = P(Y) * P( X = (x1, x2, ..., xn) | Y )

其中

P( X = (x1, x2, ..., xn) | Y ) = P( x1 | Y) * P( x2 | Y, x1) * ... P( xn | Y, x1, ... , xn-1)

这是一个超级复杂的有n个维度的条件分布,很难求出

朴素贝叶斯模型在这里做了一个大胆的假设,即X的n个维度之间相互独立,这样就可以得出:

P( X = (x1, x2, ..., xn) | Y ) = P( x1 | Y) * P( x2 | Y) * ... * P( xn | Y)

4.1.2. 朴素贝叶斯推断 目录

4.1.3. 朴素贝叶斯学习 目录

需要从训练样本中学习到以下两个参数:

  • 先验概率 P(c)

    P(c)表示了样本空间中各类样本所占的比例

    根据大数定律,当训练集中包含充足的独立同分布样本时,P(c)可根据各类样本出现的频率来估计

  • 类条件概率(又称为似然) P(xi | c)

    (1)如果 xi 是离散的,可以假设 xi符合多项式分布,这样得到 P(xi | c) 是在样本类别 c 中,特征 xi 出现的频率

    (2)如果 xi 是连续属性,可以假设 P(xi | c) ~ N( μc,i , σ2c,i )

4.2. sklearn中朴素贝叶斯类库的简介 目录

在scikit-learn中,一共有3个朴素贝叶斯的分类算法类

  • GaussianNB:先验为高斯分布的朴素贝叶斯

  • MultinomialNB:先验为多项式分布的朴素贝叶斯

  • BernoulliNB:先验为伯努利分布的朴素贝叶斯

这三个类适用的分类场景各不相同

一般来说,如果样本特征的分布大部分是连续值,使用GaussianNB会比较好

如果如果样本特征的分大部分是多元离散值,使用MultinomialNB比较合适

如果样本特征是二元离散值或者很稀疏的多元离散值,应该使用BernoulliNB。

4.2.1. GaussianNB类 目录

GaussianNB类的主要参数仅有一个,即先验概率priors

这个值默认不给出,如果不给出此时P(Y=c)= mc / m,如果给出的话就以priors 为准

在使用GaussianNB的fit方法拟合数据后,我们可以进行预测。此时预测有三种方法

  • predict方法:就是我们最常用的预测方法,直接给出测试集的预测类别输出;

  • predict_proba方法:给出测试集样本在各个类别上预测的概率;

  • predict_log_proba方法:和predict_proba类似,它会给出测试集样本在各个类别上预测的概率的一个对数转化;

from sklearn.naive_bayes import GaussianNB

clf = GaussianNB()
#拟合数据
clf.fit(X, Y)

#进行预测
clf.predict([[-0.8, -1]])

4.2.2. MultinomialNB类 目录

MultinomialNB假设特征的先验概率为多项式分布,即如下式:

MultinomialNB参数比GaussianNB多,但是一共也只有仅仅3个

  • 参数alpha:为上面的常数λ。如果你没有特别的需要,用默认的1即可。如果发现拟合的不好,需要调优时,可以选择稍大于1或者稍小于1的数

  • 参数fit_prior:是否要考虑先验概率,如果是false,则所有的样本类别输出都有相同的类别先验概率;否则可以自己用第三个参数class_prior输入先验概率,或者不输入第三个参数class_prior让MultinomialNB自己从训练集样本来计算先验概率

  • 参数class_prior:输入先验概率,若不输入第三个参数class_prior让MultinomialNB自己从训练集样本来计算先验概率

4.2.3. BernoulliNB类 目录

其中,x i 只能取0或1

BernoulliNB一共有4个参数,其中3个参数的名字和意义和MultinomialNB完全相同

唯一增加的一个参数是binarize,这个参数主要是用来帮BernoulliNB处理二项分布的。如果不输入,则BernoulliNB认为每个数据特征都已经是二元的。否则的话,小于binarize的会归为一类,大于binarize的会归为另外一类

5. 手写数字识别:sklearn包中神经网络库的使用 目录

5.1. 神经网络相关知识点回顾 目录

5.1.1. 感知机:神经网络的最小单元 目录

神经网络中最基本的成分是神经元(neuron)模型,最常见的模型是M-P神经元模型,也可以称为感知机(Perceptron)

若对生物学有一点基础的了解,就可以知道上面构造的简化的M-P神经元模型几乎完全吻合生物学上的定义:

当前神经元通过与上游神经元之间的突触结构,接受来自上游的神经元1到n传递过来的信号x1,x2...xn,由于不同的上游信号传递过来它们的影响程度是不一样的,因此对它们进行加权求和,即∑wixi,则得到总的上游信号

另外当前神经元还有一个激活阈值θ,若上游信号的汇总信号强度大于θ,即则∑wixi-θ > 0,则当前神经元被激活,处于兴奋状态;若若上游信号的汇总信号强度小于θ,即则∑wixi-θ < 0,则当前神经元未被激活,处于抑制状态

对于生物学上的神经元来说,它只有两个状态:

  • “1”:对应神经元兴奋;
  • “0”:对应神经元抑制;

则它接受的信号为上游神经元的输出为 xi∈{0,1},它的输出信号为 y∈{0,1}

则它的理想激活函数是阶跃函数,即f(x)=sgn(x)

然而,阶跃函数具有不连续、不光滑等不太好的性质,因此实际上常用sigmoid函数作为激活函数

则此时激活函数为f(x)=sigmoid(∑wixi-θ),很明显若选择sigmod函数作为感知机的激活函数,则此时感知机等价于一个logistic回归分类器

类比logistic回归分类器

  • 对于线性可分的分类任务,感知机完全等价于logistic回归分类器

  • 对于线性不可分问题,logistic回归可以构造额外的高阶多项式:

    本质上是将原始特征空间中线性不可分的样本向高维特征空间进行映射,使得它们在新的高维特征空间中线性可分

    而感知器无法进行高维空间的映射,只能基于原始特征空间寻找线性判别边界,因此感知机在面对简单的非线性可分问题是,往往无法得到理想的判别面

感知机的学习规则:

5.1.2. 神经网络的学习:BackPropagation算法 目录

神经网络的学习算法本质上是数学上常用的梯度下降(Gradient Descend)算法

依据在一轮神经网络的训练过程中所用到的训练样本的数量的不同,可分为以下两类:

  • 标准BP算法:每次网络训练只针对单个训练样本,一次训练就输入一个训练样本,更新一次网络参数;

  • 累积BP算法:每次网络训练只针对所有训练样本,一次将所有训练样本输入,更新一次网络参数;

5.1.2.1. 标准BP算法 目录

以wh,j为例进行推导

在标准BP算法中,由于只对输入的一个训练样本进行网络参数的训练,因此它的目标函数为当前样本k的均方误差Ek

此时关键在于怎么推出△whj的表达式?

根据链式求导法则,Whj的影响链条为:

因此△whj可以写成:

中间推导过程省略,最后得到的△whj的表达式为:

5.1.2.2. 累积BP算法 目录

累积BP算法的目标是最小化训练集的累积误差:

这是累积BP算法与标准BP算法的最大的也是最本质的差别

标准BP算法存在的问题:

每次更新只针对单个训练样本,参数更新得非常频繁,而且不同样本训练的效果可能出现相互“抵消”的现象

因此为了达到与累积误差相同的极小点,标准BP算法往往需要进行更多次的迭代

累积BP算法的优缺点:

  • 优点:直接对累积误差最小化,它在读取整个训练样本集D后才对参数进行一次更新,其参数更新的频率低得多

  • 缺点:累积误差下降到一点程度之后,进一步下降会非常缓慢

    此时标准BP算法往往会更快得到较好的解,因为其解的震荡性给它带来了一个好处——容易跳出局部最优

5.2. sklearn中神经网络库的简介 目录

sklearn中神经网络的实现不适用于大规模数据应用。特别是 scikit-learn 不支持 GPU

5.2.1. MLPClassifier 目录

神经网络又称为多层感知机(Multi-layer Perceptron,MLP)

sklearn中用MLP进行分类的类为MLPClassifier

主要参数说明:

参数 说明
hidden_​​layer_sizes tuple,length = n_layers - 2,默认值(100,)第i个元素表示第i个隐藏层中的神经元数量。
activation {‘identity’,‘logistic’,‘tanh’,‘relu’},默认’relu’ 隐藏层的激活函数:‘identity’,无操作激活,对实现线性瓶颈很有用,返回f(x)= x;‘logistic’,logistic sigmoid函数,返回f(x)= 1 /(1 + exp(-x));‘tanh’,双曲tan函数,返回f(x)= tanh(x);‘relu’,整流后的线性单位函数,返回f(x)= max(0,x)
slover {‘lbfgs’,‘sgd’,‘adam’},默认’adam’。权重优化的求解器:'lbfgs’是准牛顿方法族的优化器;'sgd’指的是随机梯度下降。'adam’是指由Kingma,Diederik和Jimmy Ba提出的基于随机梯度的优化器。注意:默认解算器“adam”在相对较大的数据集(包含数千个训练样本或更多)方面在训练时间和验证分数方面都能很好地工作。但是,对于小型数据集,“lbfgs”可以更快地收敛并且表现更好。
alpha float,可选,默认为0.0001。L2惩罚(正则化项)参数。
batch_size int,optional,默认’auto’。用于随机优化器的minibatch的大小。如果slover是’lbfgs’,则分类器将不使用minibatch。设置为“auto”时,batch_size = min(200,n_samples)
learning_rate {‘常数’,‘invscaling’,‘自适应’},默认’常数"。 用于权重更新。仅在solver ='sgd’时使用。'constant’是’learning_rate_init’给出的恒定学习率;'invscaling’使用’power_t’的逆缩放指数在每个时间步’t’逐渐降低学习速率learning_rate_, effective_learning_rate = learning_rate_init / pow(t,power_t);只要训练损失不断减少,“adaptive”将学习速率保持为“learning_rate_init”。每当两个连续的时期未能将训练损失减少至少tol,或者如果’early_stopping’开启则未能将验证分数增加至少tol,则将当前学习速率除以5。

MLPClassifier的训练使用BP算法,其使用交叉熵损失函数(Cross-Entropy loss function)

MLP的训练需要准备

  • Xm*n:m个训练样本的n维特征向量构成的特征矩阵

  • Ym:m训练样本的目标值组成的向量

from sklearn.neural_network import MLPClassifier

X = [[0., 0.], [1., 1.]]
y = [0, 1]

# 模型训练
clf = MLPClassifier(solver='lbfgs', alpha=1e-5, hidden_layer_sizes=(5, 2), random_state=1)
clf.fit(X, y)

# 模型预测
clf.predict([[2., 2.], [-1., -2.]])

以上训练好的MLP模型保存在clf对象中,该对象有以下两个子变量:

  • clf.coefs_:模型的一系列权重矩阵

    # 用以下命令查看每一层的权重矩阵的维度
    >>[coef.shape for coef in clf.coefs_]
    [(2, 5), (5, 2), (2, 1)]
    

    其中下标为 i 的权重矩阵表示第 i 层和第 i+1 层之间的权重

  • intercepts_:一系列偏置向量

    其中的下标为 i 的向量表示添加到第 i+1 层的偏置值

  • 多分类任务

    MLPClassifier 通过应用 Softmax 作为输出函数来支持多分类

    softmax回归本质上是将原先常见的二元分类任务神经网络的输出层采用的sigmoid激活函数换成softmax回归

    例如要利用神经网络进行k类的分类,则神经网络结构如下:

    那么最后一层即网络的输出层所采用的激活函数——softmax回归到底长什么样呢?

    因此该网络的输出层又被称为softmax layer

    因此在提供训练集时,若总共有k的类别,当某一个训练样本的类别为第i类时,它的目标值应该为[0, 0, ..., 1, ..., 0],只在向量的第i个位置标为1,其他位置都为0

  • 多标签分类任务

    一个样本可能属于多个类别。 对于每个类,原始输出经过 logistic 函数变换后,大于或等于 0.5 的值将进为 1,否则为 0。 对于样本的预测输出,值为 1 的索引位置表示该样本的分类类别

     >>> X = [[0., 0.], [1., 1.]]
     >>> y = [[0, 1], [1, 1]]
     >>> clf = MLPClassifier(solver='lbfgs', alpha=1e-5,
     ...                     hidden_layer_sizes=(15,), random_state=1)
     ...
     >>> clf.fit(X, y) 
     
     >>> clf.predict([[1., 2.]])
     array([[1, 1]])
     >>> clf.predict([[0., 0.]])
     array([[0, 1]])
    

5.3. 编程实现 目录

对于神经网络,要说它的Hello world,莫过于识别手写数字了

首先要获取实验数据,下载地址:http://www.iro.umontreal.ca/~lisa/deep/data/mnist/mnist.pkl.gz

数组中的每一行都表示一个灰度图像。每个元素都表示像素所对应的灰度值。

数据集中将数据分成3类:训练集,验证集,测试集。一般情况下会将训练数据分为训练集和测试集

为什么要将训练数据分为训练集和测试集?

将原始数据分开,保证用于测试的数据是训练模型时从未遇到的数据可以使测试更客观。否则就像学习教课书的知识,又只考教课书的知识,就算不理解记下了就能得高分但遇到新问题就傻眼了。

好一点的做法就是用训练集当课本给他上课,先找出把课本知识掌握好的人,再参加由新题组成的月考即测试集,若是还是得分高,那就是真懂不是死记硬背了。

但这样选出来的模型实际是还是用训练集和测试集共同得到的,再进一步,用训练集和验证集反复训练和检测,得到最好的模型,再用测试集来一局定输赢即期末考试,这样选出来的就更好了。

本实验中为了方便将训练集与验证集合并

  1. 先载入数据,并简单查看一下数据

    from sklearn.neural_network import MLPClassifier
    import numpy as np
    import pickle
    import gzip
    import matplotlib.pyplot as plt
    
    # 加载数据
    with gzip.open(r"mnist.pkl.gz") as fp:
        training_data, valid_data, test_data = pickle.load(fp)
    
    X_training_data, y_training_data = training_data
    X_valid_data, y_valid_data = valid_data
    X_test_data, y_test_data = test_data
    
    # 合并训练集,验证集
    X_training = np.vstack((X_training_data, X_valid_data))
    y_training = np.append(y_training_data, y_valid_data)
    
    def show_data_struct():
        print X_training_data.shape, y_training_data.shape
        print X_valid_data.shape, y_valid_data.shape
        print X_test_data.shape, y_test_data.shape
        print X_training_data[0]
        print y_training_data[0]
    
    show_data_struct()
    
  2. 随便看几张训练图片

    def show_image():
        plt.figure(1)
        for i in range(10):
            image = X_training[i]	# 得到包含第i张图的像素向量,为1*768
            pixels = image.reshape((28, 28)) # 将原始像素向量转换为28*28的像素矩阵
            plt.subplot(5,2,i+1)
            plt.imshow(pixels, cmap='gray')
            plt.title(y_training[i])
            plt.axis('off')
        plt.subplots_adjust(top=0.92, bottom=0.08, left=0.10, right=0.95, hspace=0.45,
                            wspace=0.85)
        plt.show()
    
    show_image()
    

  3. 训练模型

    为了获得比默认参数更佳的模型,我们采用网格搜索法搜索更优的训练超参数,使用gridSearchCV实现,上文3.2.2.2. 调参方法:网格搜索中有较为详细的说明

    from sklearn.model_selection import GridSearchCV
    
    mlp = MLPClassifier()
    mlp_clf__tuned_parameters = {"hidden_layer_sizes": [(100,), (100, 30)],
                                     "solver": ['adam', 'sgd', 'lbfgs'],
                                     "max_iter": [20],
                                     "verbose": [True]
                                     }
    estimator = GridSearchCV(mlp, mlp_clf__tuned_parameters, n_jobs=6)
    estimator.fit(X_training, y_training)
    

参考资料:

(1) 【GitHub】MLjian/TextClassificationImplement

(2) 刘建平Pinard《scikit-learn 逻辑回归类库使用小结》

(3) 机器学习sklearn19.0——Logistic回归算法

(4) 刘建平Pinard《scikit-learn决策树算法类库使用小结》

(6) 刘建平Pinard《scikit-learn 支持向量机算法库使用小结》

(7) 刘建平Pinard《支持向量机高斯核调参小结》

(8) loveliuzz《机器学习sklearn19.0——SVM算法》

(9) 周志华《机器学习:第7章 贝叶斯分类器》

(10) 刘建平Pinard《朴素贝叶斯算法原理小结》

(11) 刘建平Pinard《scikit-learn 朴素贝叶斯类库使用小结》

(12) 周志华《机器学习:第5章 神经网络》

(13) 吴恩达《deeplearning.ai:改善深层神经网络》

(14) scikit-learn中文网《神经网络模型(有监督)》

(15) 啊噗不是阿婆主《sklearn 神经网络MLPclassifier参数详解》

(16) 多问Why.简书《SkLearn之MLP》