对数据标准化;优化模型通过加宽,加深
声纳数据集区分岩石和金属,输出变量是一个字符串“M”和“R”我岩石,它将需要转化为整数 1 和 0 。
import numpy
import pandas
from keras.models import Sequential
from keras.layers import Dense
from keras.wrappers.scikit_learn import KerasClassifier
from sklearn.model_selection import cross_val_score#交叉验证的分数结果
from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import StratifiedKFold#用于交叉验证
#from sklearn.preprocessing import StandardScaler#标准化
#from sklearn.pipeline import Pipeline
seed = 7
numpy.random.seed(seed)#总得到相同的随机数序列
dataframe = pandas.read_csv("sonar.csv", header=None) # 加载数据集,用的数据框,header=None:第一行的数据列名去掉
dataset = dataframe.values
#将列向量分割成60输入变量(X)和1个输出变量(Y)
X = dataset[:, 0:60].astype(float) # 分割为60个输入变量,属性个数为60,转化为浮点类型
Y = dataset[:, 60] # 1个输出变量,输出变量是字符串类型,后面要把r,m转化成0,1
我们可以使用从scikit-learn LabelEncoder类。这个类通过 fit() 函数获取整个数据集模型所需的编码,然后使用transform()函数应用编码来创建一个新的输出变量。
#不是数值类型要进行转换,类别标签数值化,使类别标签转化为数字标签
encoder = LabelEncoder()
encoder.fit(Y)
encoded_Y = encoder.transform(Y)#Y进行编码,转化为新的输出变量,为0,1
# 基准模型
def create_baseline():
#create model创建模型
model = Sequential()#定义基准模型
model.add(Dense(60, input_dim=60, kernel_initializer='normal', activation='relu'))#60个全连接隐含层
model.add(Dense(30, kernel_initializer='normal', activation='sigmoid'))
model.add(Dense(1, kernel_initializer='normal', activation='sigmoid'))
# Compile model编译模型
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])#loss='binary_crossentropy'对数损失函数;optimizer='adam'优化函数,做梯度下降
return model
交叉验证
K-fold交叉评估模型验证
10交叉:把数据分成10份,每次取出9份做训练,留一份做测试,轮流取,直到每一份都有且仅有做过一次测试,这样一共轮流10次
# evaluate model with standardized dataset
#start_time = time.time()
estimator = KerasClassifier(build_fn=create_baseline, nb_epoch=100, batch_size=5, verbose=0)#build_fn创建基线模型,nb_epoch=100指迭代100次;
kfold = StratifiedKFold(n_splits=10, shuffle=True, random_state=seed)#n_splits=10 10份;shuffle=True,随机打乱分random_state=seed;定义交叉验证怎么分
results = cross_val_score(estimator, X, encoded_Y, cv=kfold)
print("Baseline: %.2f%% (%.2f%%)" % (results.mean()*100, results.std()*100))#结果的精确度和平均标准差打印出来,10个结果的平均数是一轮下来交叉验证的最终结果
#end_time = time.time()
#print"用时: ", end_time - start_time
batch_size调参:首先,如果训练集较小,直接使用batch梯度下降法(batch size 等于样本集大小)。如果样本数目较大,一般的mini-batch大小为64到512。考虑到电脑内存设置和使用的方式,如果mini-batch大小是2的 n 次方,代码会运行地快一些。当内存不够的时候要选取小的batch值。
使用scikit-learn 的 StandardScaler 类来标准化声纳数据集。
标准化:让数据标准化同一个尺度,使每个属性的平均值为0,方差为1。
在训练集而不是整个数据集上对数据进行标准化, 通过运行交叉验证和训练过的标准化数据去准备“未知”的训练数据。这让标准化在交叉验证中成为模型准备的一步, 也防止了算法在评估期间获得了数据准备过程对测试集的记忆。
利用 scikit-learn 的 Pipeline 类来实现这个过程。Pipeline 是一个包装器, 在交叉验证过程的执行一个或多个模型。在这里,我们可以定义一个Pipeline 带有一个tandardScaler, 后面紧跟着就是我们的神经网络模型。
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline#pipeline为包装器
numpy.random.seed(seed)
estimators = []
estimators.append(('standardize', StandardScaler()))#标准化的方式,最后一个函数,把数据放到平均值标准差为1,0
estimators.append(('mlp', KerasClassifier(build_fn=create_baseline, nb_epoch=100, batch_size=5, verbose=0)))#mlp为多层感知机,后面是训练方式
pipeline = Pipeline(estimators)#把上述两行程序都装进去,标准化的过程和训练方式全部装进去
kfold = StratifiedKFold(n_splits=10, shuffle=True, random_state=seed)#5交叉验证
results = cross_val_score(pipeline, X, encoded_Y, cv=kfold)#采用交叉验证的方式去运行
print("Standardized: %.2f%% (%.2f%%)" % (results.mean()*100, results.std()*100))
#end_time = time.time()
#print"用时: ", end_time - start_time
注释掉隐藏层30个神经元的部分得出的结果明显提升
def create_baseline():
#create model
model = Sequential()
model.add(Dense(60, input_dim=60, kernel_initializer='normal', activation='relu'))
#model.add(Dense(30, kernel_initializer='normal', activation='sigmoid'))
model.add(Dense(1, kernel_initializer='normal', activation='sigmoid'))
# Compile model
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
return model
结果显示:
注:一般评估一个更大型的网络:对模型做调整,额外再隐藏层加一个较小的隐藏层,性能应该有很好的提升,但是这里去掉了隐藏层性能却得到很好的提升,因为交叉验证划分数据集是随机的。
这里原本:60 input->[60->30]->1 output变为60 input->[60]->1 output 居然性能提升了。。。。!!!
评估一个更小型的网络:
限制第一层的特征数量,将基准模型的60个输入变量减少到30,迫使神经网络从输入数据中提取最重要的结构,结果稍微提升
def create_baseline():
#create model
model = Sequential()
model.add(Dense(30, input_dim=60, kernel_initializer='normal', activation='relu'))
model.add(Dense(1, kernel_initializer='normal', activation='sigmoid'))
# Compile model
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
return model
结果显示:
所以神经网络的结构会影响性能 ,但目前为止没有好的方法告诉你,怎么改网络结构性能会提升,只有唯一的办法:多试
改代码,调参数。
原创中文链接:利用人工神经网络框架Keras解决二分类问题 —— Jinkey 翻译