有监督学习:训练的数据包含已知的结果。模型相对于这些结果进行训练。
无监督学习:训练的数据不包含任何已知的结果。算法自行发现数据中的联系。
每个神经元都包含一个激活函数和一个阈值。阈值是输入信息激活神经元所必需的最小值。0~1,-1 ~ 1。
神经元的作用是对输入信号进行加权求和并应用于激活函数。输入层将数据传递给第一个隐藏层。然后隐藏层神经元将加权信息传输到输出层神经元。
ps1:随机梯度下降算法必须是可微的,如果函数有界会很有帮助。
ps2:隐藏层节点的激活函数将非线性引入网络中。
神经网络的大小通常由需要顾及的参数数量来度量。
sigmoid函数(logistic):接收实数值,将其压扁到0-1的范围。函数的输出可被解释为人工神经元发射的概率。(运算成本低) f(u) = 1/1+exp(-cu)。c是参数,eg.1.5.
反向传播法:1.确定权重初始值。2.前向反馈。3.误差评估。4.使用输出层的误差重新调整权重。并计算想对于权重值变化的误差变化的梯度。5.以降低变化梯度对权重做出调整。根据激活函数的导数,网络输出和实际目标结果之间的偏差,以及神经元输出调整每个神经元的权重和偏差。神经网络通过设置随机值的权重和偏差进行初始化,随机值设置在(-2n~2n)内,其中n是输入属性的数量。
梯度下降算法容易陷入局部极小值的境地,解决方法
1.指定一个冲量参数
2.使用随机梯度下降(SGD):随机选择样本来更新参数,并在该样本的相关梯度上移动,遵寻一条曲折的通往极小值的梯度路径。
SGD的一个非常好的理论特性是,如果损失函数是凸的,那么保证能找到全局最小值。
可以将DNN视为多个回归模型的组合,在某些情况下,我们可以将每个隐藏层解释为一个简单的对数线性模型。
在图像压缩中,使用线性整流(ReLu)激活函数,用在隐藏层的激活函数上。因为“得到更好的网络泛化,并减少实际的压缩–解压时间。”
如何快速地近似任何函数:一个隐藏层足以模拟任何分段连续函数。
来自研究人员Hornik等人的定理:设F是n维空间有限子集上的连续函数,那么存在一个包含有限个隐藏单元的双层神经网络F^,它近似等于F,对于F域中的所有的x,I F(x) - F^(x)
有监督学习:有监督学习的基本目标是给定训练样本{xi,yi}的预测器。给定这样一组样本对,学习算法构造一个预测器,将实际映射到标签上。然后可以使用预测器从新的样本中预测y的适当值。如果y是真实值,那么做的是回归任务;如果y是无需的有限集合中的值那么做的是模式分类。
无监督学习:在无监督学习中,没有已标注的样本可以用来推断。无监督学习的关键是在于找到数据中的有用信息。
无监督学习利用数据中的特征,如可变性和可分性,来确定属性/特征的相关性。无监督学习的目标是将一组未标注的数据分成不同的种类或者聚类。
半监督学习:使用大量未标注数据和非常少量的标注数据。它可以在只有有限的带标注的观测值的情况下使用。
ps这里提供一个sklearn的软件包功能,可以轻松构建训练样本和测试样本。train_test_split方法。
import random
from sklearn.cross_validation import train_test_split
np.random.seed(2016)
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size = 0.2)
即把20%的数据作为测试集,其他80%用来训练模型。
学习速率决定了梯度下降算法达到极小值的步长大小。网络在大学习速率下会较快速的学习,但学习速率过快可能会导致错过全局最小值,学习速率过慢则需要较长时间才能找到最佳极小值。
“最佳学习速率通常接近最大学习速率的一半,不会造成训练标准的偏差…………从一个大的学习速率开始,如果偏离了训练标准,则再次尝试该学习速率的1/3值,如此反复直到没有观察到偏离为止。”
fit函数用于将指定的模型拟合到实际的数据。函数接收参数,训练属性存储在x_train中,目标储存在y_train中。
print “fitting the model right now”
fit1.fit(x_train,y_train)
有许多技术可以评估模型性能。最直接的就是测量预测值和实际目标值之间的相关性。对于一个完美拟合,观测到的相关性应该为1. 由于相关系数的范围是在0-1之间,因此常常记录平方相关系数,0—1之间。
另一个流行的度量是均方差(MSE),它测量的是观测目标和预测值之间误差的平均值,
RMSE可以解释为以目标变量为单位度量的预测值和观测值之间的平均距离。
sigmoid函数的一个局限性是当x增大或减小的时候,他的梯度变得越来越小,如果使用梯度下降或类似的方法,这就是一个问题。该问题成为梯度消失问题,随着梯度的变小参数值的变化导致网络输出的变化就会很小,极大的减慢了学习的速度。由于网络输出层的梯度相对于前面层中的参数变得非常小。因此随着层数的增加,学习速度的降低将会被放大。特别是压缩在0-1区间的中,即使输入中一个非常大的变化,也只会产生一个很小的输出变化。
掌握另一个激活函数,用一个非挤压式的函数替换掉一个挤压式的激活函数。其中之一是线性整流单元(ReLU)它的定义是:f(x)= max (0,x),
x是神经元输出,该函数进行一个阈值操作,任何小于0的输入值被设置为0.显著提高了语音识别和计算机视觉任务的分类率,简单的取最大操作让他比s形激活函数的网络要快的多,这也提高了神经网络的稀疏性。因为随机初始化的时候,整个网络中大约一半的神经元将被设置为0.
如果神经元的输出接近1,你可以认为他是”活跃的“,如果输出值接近于0,则认为是“不活跃的”。稀疏性把神经元在大部分时间限制在不活跃的状态。这通常会得到更好的泛化性能。
如果将每一个隐藏层视为一个特征检测器,层数越多,就可以学习到越复杂的特征检测器。这就总结出一个简单的经验法则-----函数越复杂,需要使用的层数就越多。 在一些情况下面,使用100次迭代就够了,有的情况10000次可能都不够。迭代的次数很大程度上取决于,样本数据的特征,网络拓扑结构,使用的激活函数,应用的学习算法,甚至网络被设计用来解决的人物的可接受的误差的阈值。
如何快速改进模型-------奥卡姆剃刀(Ocams Razor)法则
如果较小的一组属性能充分拟合观测值,便使用这些属性。避免“叠加”附加属性来提高模型的拟合度。
选择需要最少的假设的建模方法。
只保留那些与假设的预测有明显差异的假定子集。
如果几种假设能同样好地解释一种现象,通常在开始选择最简单的一个。
如果两个或更多模型具有相同的预测精度,请选择最简单的模型。
避免过度拟合(eg-音乐上拟合音乐,结果是模型完美的拟合了音乐和噪声。)说明模型太过复杂,过度拟合的关键的结果对未来(不可见的)数据的泛化(预测)能力较差。
——————为了降低深度神经网络的复杂度并提高泛化能力的一个常见的网络限制的方法是正则化,正则化限制了模型的复杂性,使得模型相对于预测或分类问题不会太过于复杂。这可以获得更好的泛化(预测)结果。不进行正则化,你的模型可能因为太过复杂而过度拟合,或者因为太简单而欠拟合,这两种情况都会导致很差的预测结果。
除非绝对必要,正则化将通过抑制网络权重避免其变得非常强大。添加衰减参数来惩罚较大的权重来实现的。
该模型的MSE比没有正则化的模型略高,但不是高很多。鉴于差异不大,并且为了响应简约法则,我们将选择fit4作为最终模型。
在构建DNN模型时,请牢记这一点,为了获得最好的泛化能力,DNN应该用尽可能少的神经元来解决手头的问题,并且有一个可容忍的误差。训练模式的数量越多,可以使用的神经元越多,同时能仍然保持DNN的泛化能力。
from scipy.stats.stats import pearsonr
correl = pearsonr(pred4_test, y_test)
然后我们可以打印出相关性和R的平方
print “Test correlation is”, correl[0]
Test correlation is [0.9073899]
print "Test R^2 is", correl[0]*correl[0]
Test R^2 is [0.82335643]
冻结网络权重后可以将其用于未来的数据,而不用重新训练
fitFr = Regressor(
layers = [
Layer("Rectifier", units=6, frozen = True),
Layer("Rectifier", units=14,frozen=True),
Layer("Linear")],
learning_rate=0.02,
random_state = 2016,
regularsize = "L2"
weight_decay = 0.001,
n_iter = 100)
在这个例子是冻结了所有的层,也可以冻结特定的层,如果你想调查非冻结层的权重如何响应输入属性,这样做就会很有用。
保存fit4
import pickle
pickel.dump(fit4,open('Boston_fit4.pkl','wb'))
在下面,我们打开之前保存为Boston_fit4.pkl(fit4)的网络,并储存在Python对象model中:
model = pickle.load(open('Boston_fit4.pkl','rb'))
注意:以下代码表示找到你的工作路径:
import os
print os.getcwdu()
c:\deepnetworks
在这个例子中,工作路径是C:\deepnetworks。如果使用pickle.dump保存深度神经网络,文件会保存在这个目录中。
下面是获取数据的代码`
import numpy as np
import urllib
url = "http://goo.gl/j0Rvxq"
raw_data = urllib.urlopen(url)
dataset = np.loadtxt(raw_data, delimiter=",")
通常使用pandas处理数据比较容易,特别是对于检查和初始的完整性验证,因此我们把数据转换到一个pandas dataframe之中
import panda as pd
from pandas import DataFrame
data = pd.DataFrame(dataset)
处理丢失数据和观测值(不是所有的数据都要被改成nan)
1.把缺少的值换成符号“nan”
data= data.replace(0,np.nan)
这样就把所有的缺少数据改成了nan
2.首先把第一个特征中的nan改成0
data[0].fillna(0,inplace=True)
3.将第八个目标属性nan改成-1
data[8].filla(-1,inplace=True)
4.然后可以用count函数来看下有多少实际的观测值
print data.count()
这时候发现有的属性中有过多的缺失值,
这时候的简单的办法就是用一个合理的值来推测缺失的观测值。复杂的办法就是对数据使用一个分布模型(如最大似然和多重插补)
鉴于某两个属性中有大量的缺失值,我们把这两个属性从样本中去掉,并且使用drop的办法去掉其他剩下的缺失值。(第3,4个属性值被去掉)
data = data.drop(3,1)
data = data.drop(4,1)
data = data.dropna()
现在有724组样本,8-2=6组特征,1个目标
现在创建python对象来保存属性和目标变量
y = data[8]
data = data.drop(8,1)
x = data
将数据用与二元分类神经网络之前,我们需要对其进行标准化。like above
from sklearn import preprocessing
x_MinMax = preprocessing.MinMaxScaler()
y_MinMax = preprocessing.MinmaxScaler()
y.as_matrix(y)
y = np.array(y).reshape((len(y),1))
x = np.array(x).reshape((len(x),6))
x = x_MinMax.fit_transform(x)
y = y_MinMiax.fit_transform(y)
x.mean(axis=0)
保存数据到指定位置
完成上述工作之后,最好把数据保存起来,构建神经网络是一个交互过程,你一定不会想在每次模型运行是都需要访问资源库。此外,你不会想从相同的机器过于频繁的访问UCI机器学习资料库,因为这会增加网络协议被齐屏蔽的风险,最好把数据离线保存起来。
把loc设置成保存数据的路径
cleaned_data = np.column_stack((y,x))
loc ="C:\\mydatasets\\PimaIndians_CleanData.txt"
np.savetxt(loc,cleaned_data)
每个迭代的步长由学习速率控制,较大的步长降低了训练时间,但是增加了被局部极小值捕获的可能性。另一个帮助网络脱离局部最小值的技术是使用冲量。它的取值是在0-1之间。一个较高的冲量参数值能减少训练时间,并且帮助网络避免被局部极小值捕获。使用大冲量来降低学习速率.
训练样本观测值的20%~25%用于留出验证。
1.打开保存的本地文件
import numpy as np
loc = "C:\\maydatasets\\PimaIndains_CleanData.txt"
data = np.loadtxt(loc.skiprows=0)
y = data[:,5]
x = data[:1:5]
2.生成训练集和测试集
用sklearn.cross_validation 生成训练和测试集:
import random
from sklearn.cross_validation import train_test_split
np.random.seed(2016)
x_train,x_test,y_train,y_test =
train_test_split(x,y,test_size = 0.2)
3.指定模型
我们用sknn.mlp来构建模型,所构建模型有3个隐藏层,在第一,第二和第三层分别有45,18,和18个神经元,所有隐藏层使用sigmoid激活函数,输出层使用softmax激活函数
将节点输出值转化为后验概率:
from sknn.mlp import Classfier, Layer
fit1 = Classifier(
layers=[
Layer("Sigmoid", units = 45)
Layer("Sigmoid", units = 18)
Layer("Sigmoid", units = 18)
Layer("Softmax")],
learning_rate=0.80,
random_state = 2016,
valid_size = 0.25,
learning_momentum = 0.30,
n_iter=100)
4.拟合模型
调用fit函数:
print"fitting model right now"
fit1.fit(x_train, y_train)
模型收敛完毕后,使用predict_proba函数来观察分类成员的预测概率:
prob = fit1.predict_proba(x_train)
后根据混淆矩阵发现模型的不可行性
随机省略一部分隐藏的神经元的过程叫做随机失活(dropout)
(Tanh)反曲s形状。与sigmoid函数不同,这个是0对称的,因为他的输出范围较宽,在复杂非线性关系建模时,有时候更有效。
一个批次由一个前向/反向传播的多个训练样本组成 ?代替? 原始随机梯度下降算法中的针对每个单独的样本计算梯度。
针对上述讲解重建模型
fit2 = Classifier(
layers=[
Layer("Tanh", units = 45)
Layer("Tanh", units = 18)
Layer("Tanh", units = 18)
Layer("Softmax")],
learning_rate=0.80,
random_state = 2016,
valid_size = 0.25,
dropout_rate = 0.20,
learning_momentum = 0.30,
batch_size = 35,
n_iter=100)
valid_size = 0.25,是指模型指定其中25%用于验证。
接下来,拟合模型查看混淆矩阵
print"fitting model right now"
fit2.fit(x_train, y_train)
pred2_train = fit2.predict_proba(x_train)
confu2 = confusion_matrix(y_train, pred2_train)
print confu2
[[332 44]
[100 103]]
性能准确率=(332+103)/579 =75.12%
可以用python计算
score2 = fit2.score(x_train, y_train)
print score2
此处通过混淆矩阵可以看出,这是一个不平衡样本,
y = -1 时,模型准确率 = 332/(332+44)= 0.8829
y = 1 时,模型准确率=103/(103+100)= 0.5074
此时应该使用平均类别准确率= (88.29%+50.74%)=69.52% 明显小于之前计算的准确率。
解决的办法是重新对样本进行采样,演示一下,我们对较小的样本进行采样,权重是1.10,设置所需对象
w_train = x_train[:,0]
w_train[y_train == 0] = 1
w_train[y_train == 1] = 1.10
然后指定模型拟合
fit3 = Classifier(
layers=[
Layer("Tanh", units = 45)
Layer("Tanh", units = 18)
Layer("Tanh", units = 18)
Layer("Softmax")],
learning_rate=0.80,
random_state = 2016,
valid_size = 0.25,
dropout_rate = 0.20,
learning_momentum = 0.30,
batch_size = 35,
n_iter=100)
print"fitting model right now"
fit3.fit(x_train, y_train)
pred3_train = fit3.predict_proba(x_train)
score3 = fit3.score(x_train, y_train)
print score3
0.746113989637
看到整体准确率更低,但是当我们查看混淆矩阵,
confu3 = confusion_matrix(y_train, pred3_train)
print confu3
[[353 23]
[124 79]]
评价类别准确率有77.48%,好很多。
PS。需要注意的是,类别频率会影响判定边界,如果过度纠正训练样本中的类别不平衡,测试样本的性能可能会更差,
查看在测试集上的表现。
最后一项任务是评估选定模型在真实测试集上的表现。
score_test3 = fit3.score(x_test, y_test)
print score_test3
0.765517241379
pred_test3 = fit3.predict(x_test)
confu3_test = confusion_matrix(y_test, pred_test)
print confu3_test
[[93 6]
[28 18]]
接下来保存创建的模型
import os
import pickle
pickle.dump(fit1, open('Pima_fit1.pkl',''wb'))
pickle.dump(fit2, open('Pima_fit1.pkl',''wb'))
pickle.dump(fit3, open('Pima_fit1.pkl',''wb'))
rmsprops算法:对每个更新向量分量使用不同的学习速率。它使用每个参数的梯度幅度的指数移动平均值除以该平均值的平方根对梯度进行归一化。
fit1 = Classifier(
layers=[
Layer("Tanh", units = 21)
Layer("Tanh", units = 30)
Layer("Sigmoid", units = 37)
Layer("Softmax")],
learning_rate=0.30,
random_state = 2016,
learning_rule = u'rmsprop'
valid_size = 0.25,
dropout_rate = 0.20,
learning_momentum = 0.005,
batch_size = 35,
n_iter=100)
Adagrad学习算法:对训练样本中很少出现的特征使用较大的学习速率,降低稀疏特征的学习速率。
关键::Adagrad通过结合过去观测值的几何结构来采用一个适应特定特征的学习速率。
learning_rule = u'adagrad'
Nesterov加速梯度下降算法:一阶优化方法,提高稳定性,并加快常规梯度下降的收敛速度。在常规梯度下降中更新了一个冲量。
Nesterov的加速梯度算法已经被证明是平滑凸优化的最佳方法
learning_rule = u"nesterov"
尝试冲量法
learning_rule = u'momentum'
常规随机梯度下降
learning_rule = u'sgd'
冲量法比常规sgd收敛速度快,并且增加了网络收敛的学习速率范围。
Adadelta算法:是Adagrad算法的一种改进,它使用固定大小的窗口上的累积的梯度平方和。在这种情况下,分母不能积累到无穷大,而作为一个使用最近梯度的局部估计,可以在每次迭代上继续学习,而不是像Adagrad算法那样慢下来。