Python深度学习02——Keras多层感知机(MLP)实现

参考书目:陈允杰.TensorFlow与Keras——Python深度学习应用实战.北京:中国水利水电出版社,2021

本系列基本不讲数学原理,只从代码角度去让读者们利用最简洁的Python代码实现深度学习方法。


多层感知机

多层感知机就是指在神经网络里面加一个或多个非线性的隐藏层 ,让其能够更加普遍的处理函数关系。

通用近似定理表明,就算只有一个隐藏层的神经网络,也能够拟合这个世界上所有的函数(当然只是理论,具体实现效果不一定好,因为你很难找到每种函数对应的神经元需要多少个)
多层感知机和其他机器学习算法一样,接受二维矩阵的输入,可以用于回归或者分类问题。接下来分别介绍Python案例。

Kears里面的多层感知机主要是通过Dense层实现,这个叫全连接层,又叫稠密层。很多个Dense层堆一起就是多层感知机。


多层感知机Python分类案例

分类问题采用最经典的泰坦尼克号数据集,响应变量是是否存活,读取数据,导入包

import pandas as pd
from keras.models import Sequential
from keras.layers import Dense

载入数据集
df = pd.read_csv("./titanic_data.csv")
df.shape
# 查看前5条记录
print(df.head())
df.head().to_html("Ch6_2_1a_01.html")
# 显示数据集的描述资料  
print(df.describe())
df.describe().to_html("Ch6_2_1a_02.html")

# 显示数据集的信息
print(df.info())
# 显示没有数据料的条数
print(df.isnull().sum())

该数据有一定的缺失值,进行预处理

import numpy as np
seed = 7
np.random.seed(seed)

# 删除不需要的栏位 
df = df.drop(["name", "ticket", "cabin"], axis=1)
#  处理遗失数据
df[["age"]] = df[["age"]].fillna(value=df[["age"]].mean())
df[["fare"]] = df[["fare"]].fillna(value=df[["fare"]].mean())
df[["embarked"]] = df[["embarked"]].fillna(value=df["embarked"].value_counts().idxmax())
print(df["embarked"].value_counts())
print(df["embarked"].value_counts().idxmax())
# 转换分类数据
df["sex"] = df["sex"].map( {"female": 1, "male": 0} ).astype(int)
# Embarked栏位的One-hot编码
enbarked_one_hot = pd.get_dummies(df["embarked"], prefix="embarked")
df = df.drop("embarked", axis=1)
df = df.join(enbarked_one_hot)
# 将标签的 survived 栏位移至最后  
df_survived = df.pop("survived") 
df["survived"] = df_survived
print(df.head())
df.head().to_html("Ch6_2_2.html")
#  分割成训练(80%)和测试(20%)数据集 
mask = np.random.rand(len(df)) < 0.8
df_train = df[mask]
df_test = df[~mask]
print("Train:", df_train.shape)
print("Test:", df_test.shape)

#储存处理后的数据 
df_train.to_csv("titanic_train.csv", index=False)
df_test.to_csv("titanic_test.csv", index=False)

 下面开始正式建模,首先读取数据,取出X和y,标准化

# 载入Titanic的训练和测试数据集
df_train = pd.read_csv("./titanic_train.csv")
df_test = pd.read_csv("./titanic_test.csv")
dataset_train = df_train.values
dataset_test = df_test.values

# 分割成特征数据和标签数据
X_train = dataset_train[:, 0:9]
Y_train = dataset_train[:, 9]
X_test = dataset_test[:, 0:9]
Y_test = dataset_test[:, 9]
# 特征标准化
X_train -= X_train.mean(axis=0)
X_train /= X_train.std(axis=0)
X_test -= X_test.mean(axis=0)
X_test /= X_test.std(axis=0)

构建MLP模型,打印查看模型信息

#  定义模型
model = Sequential()
model.add(Dense(11, input_dim=X_train.shape[1], activation="relu"))
model.add(Dense(11, activation="relu"))
model.add(Dense(1, activation="sigmoid"))
model.summary()   # 显示模型摘要信息  

 sequential表示这是一个顺序堆叠的模型,前两个Dense是隐藏层,神经元个数都为11,最后一个是输出层,由于是二分类问题,可以采用sigmoid激活函数。254表示有254个参数需要学习。

下面编译模型,进行训练

# 编译模型
model.compile(loss="binary_crossentropy", optimizer="adam",
              metrics=["accuracy"])
#训练模型
print("Training ...")
history = model.fit(X_train, Y_train, validation_split=0.2, 
          epochs=100, batch_size=10)

 训练过程会展示每轮数据,有训练集损失和精度,验证集损失和精度

训练完后去评估模型精度

# 评估模型
print("\nTesting ...")
loss, accuracy = model.evaluate(X_train, Y_train)
print("训练数据集的准确度 = {:.2f}".format(accuracy))
loss, accuracy = model.evaluate(X_test, Y_test)
print("測测试数据集的准确度 = {:.2f}".format(accuracy))

 画出损失

# 显示图表来分析模型的训练过程  
import matplotlib.pyplot as plt
# 显示训练和验证损失
loss = history.history["loss"]
epochs = range(1, len(loss)+1)
val_loss = history.history["val_loss"]
plt.plot(epochs, loss, "b-", label="Training Loss")
plt.plot(epochs, val_loss, "r--", label="Validation Loss")
plt.title("Training and Validation Loss")
plt.xlabel("Epochs")
plt.ylabel("Loss")
plt.legend()
plt.show()

 画出准确率(精度)

# 显示训练和验证准确度
acc = history.history["accuracy"]
epochs = range(1, len(acc)+1)
val_acc = history.history["val_accuracy"]
plt.plot(epochs, acc, "b-", label="Training Acc")
plt.plot(epochs, val_acc, "r--", label="Validation Acc")
plt.title("Training and Validation Accuracy")
plt.xlabel("Epochs")
plt.ylabel("Accuracy")
plt.legend()
plt.show()

 可以看出验证集损失在18轮之后就一直上升,可能过拟合,下面重新构建模型,只训练18轮

model = Sequential()
model.add(Dense(11, input_dim=X_train.shape[1], activation="relu"))
model.add(Dense(11, activation="relu"))
model.add(Dense(1, activation="sigmoid"))
# 编译模型
model.compile(loss="binary_crossentropy", optimizer="adam",metrics=["accuracy"])
# 训练模型
print("Training ...")
model.fit(X_train, Y_train, epochs=18, batch_size=10, verbose=0)
# 评估模型
print("\nTesting ...")
loss, accuracy = model.evaluate(X_train, Y_train)
print("训练数据集的准确度 = {:.2f}".format(accuracy))
loss, accuracy = model.evaluate(X_test, Y_test)
print("测试数据集的准确度 = {:.2f}".format(accuracy))

当然神经网络的隐藏层个数,神经元个数,还有迭代系数都是可以改的,是一个反复调参的过程。

下面将运行好的模型的参数进行存储(因为神经网络计算量大,不可能每次都是现学现用(太浪费时间....),可以把之前学好的模型进行参数存储,下次可以直接读取使用)

# 存储Keras模型
print("Saving Model: titanic.h5 ...")
model.save("titanic.h5")

然后可以这样读取使用

# 建立Keras的Sequential模型
model = Sequential()
model = load_model("titanic.h5")
# 编译模型
model.compile(loss="binary_crossentropy", optimizer="adam",metrics=["accuracy"])
# 评估模型
loss, accuracy = model.evaluate(X_test, Y_test)
print("测试数据集的准确度= {:.2f}".format(accuracy))

预测,计算混淆矩阵

predict=model.predict(X_test) 
# Y_pred=np.argmax(predict,axis=1)
Y_pred = np.int64(predict>0.5)
y_pred = np.squeeze(Y_pred)
y_pred[:5]

#print(Y_test.astype(int))
#显示混淆矩阵
tb = pd.crosstab(Y_test.astype(int), y_pred,
                 rownames=["label"], colnames=["predict"])
print(tb)


多层感知机Python回归案例

回归问题依旧采用最常用的波士顿房价数据集,导包,读取数据,标准化

import numpy as np
import pandas as pd
from keras.models import Sequential
from keras.layers import Dense

np.random.seed(7)  # 指定乱数种子
#  载入波士顿房屋数据集
df = pd.read_csv("./boston_housing.csv")
dataset = df.values
np.random.shuffle(dataset)  #  用乱数打乱数据
# 分割成特征数据和标签数据
X = dataset[:, 0:13]
Y = dataset[:, 13]
#  特征标准化
X -= X.mean(axis=0)
X /= X.std(axis=0)
# 分割训练和测试数据集
X_train, Y_train = X[:404], Y[:404]     # 训练数据前404条
X_test, Y_test = X[404:], Y[404:]       #  测试数据后 102条

定义模型

# 定义模型
def build_model():
    model = Sequential()
    model.add(Dense(32, input_shape=(X_train.shape[1],), activation="relu"))
    model.add(Dense(1))
    # 编译模型
    model.compile(loss="mse", optimizer="adam", 
                  metrics=["mae"])
    return model

手工使用K折交叉验证进行模型的调优,分为4折

k = 4
nb_val_samples = len(X_train) // k
nb_epochs = 80
mse_scores = []
mae_scores = []

for i in range(k):
    print("Processing Fold #" + str(i))
    # 取出验证数据集
    X_val = X_train[i*nb_val_samples: (i+1)*nb_val_samples]
    Y_val = Y_train[i*nb_val_samples: (i+1)*nb_val_samples]
    # 结合出训练数据集 
    X_train_p = np.concatenate(
            [X_train[:i*nb_val_samples],
            X_train[(i+1)*nb_val_samples:]], axis=0)
    Y_train_p = np.concatenate(
            [Y_train[:i*nb_val_samples],
            Y_train[(i+1)*nb_val_samples:]], axis=0)
    model = build_model()
    # 训练模型
    model.fit(X_train_p, Y_train_p, epochs=nb_epochs, 
              batch_size=16, verbose=0)
    #评估模型
    mse, mae = model.evaluate(X_val, Y_val)
    mse_scores.append(mse)
    mae_scores.append(mae)

计算训练集测试集的平均损失

print("MSE_val: ", np.mean(mse_scores))
print("MAE_val: ", np.mean(mae_scores))
# 使用测试数据评估模型
mse, mae = model.evaluate(X_test, Y_test)    
print("MSE_test: ", mse)
print("MAE_test: ", mae)

可以换更深的神经网络模型,然后再次评价

def build_deep_model():
    model = Sequential()
    model.add(Dense(32, input_shape=(X_train.shape[1],), activation="relu"))
    model.add(Dense(16, activation="relu"))
    model.add(Dense(1))
    #  编译模型
    model.compile(loss="mse", optimizer="adam", metrics=["mae"])
    return model

k = 4
nb_val_samples = len(X_train) // k
nb_epochs = 80
mse_scores = []
mae_scores = []
for i in range(k):
    print("Processing Fold #" + str(i))
    # 取出验证数据集
    X_val = X_train[i*nb_val_samples: (i+1)*nb_val_samples]
    Y_val = Y_train[i*nb_val_samples: (i+1)*nb_val_samples]
    # 结合出训练数据集
    X_train_p = np.concatenate(
            [X_train[:i*nb_val_samples],
            X_train[(i+1)*nb_val_samples:]], axis=0)
    Y_train_p = np.concatenate(
            [Y_train[:i*nb_val_samples],
            Y_train[(i+1)*nb_val_samples:]], axis=0)
    model = build_deep_model()
    #训练模型
    model.fit(X_train_p, Y_train_p, epochs=nb_epochs, batch_size=16, verbose=0)
    # 评估模型
    mse, mae = model.evaluate(X_val, Y_val)
    mse_scores.append(mse)
    mae_scores.append(mae)
    
print("MSE_val: ", np.mean(mse_scores))
print("MAE_val: ", np.mean(mae_scores))
#使用测试资料评估模型
mse, mae = model.evaluate(X_test, Y_test)    
print("MSE_test: ", mse)
print("MAE_test: ", mae)

当然,k折的k数量也是可以改的

选出最优模型后,可以进行所有数据的拟合和评价

df = pd.read_csv("./boston_housing.csv")
dataset = df.values
np.random.shuffle(dataset)  # 使用乱数打乱资料
# 分割成特征数据和标签数据
X = dataset[:, 0:13]
Y = dataset[:, 13]
# 特征标准化
X -= X.mean(axis=0)
X /= X.std(axis=0)
# 分割训练和测试数据集
X_train, Y_train = X[:404], Y[:404]     # 训练数据前404条
X_test, Y_test = X[404:], Y[404:]       # 测试数据后 102条
# 定义模型
model = Sequential()
model.add(Dense(32, input_shape=(X_train.shape[1],), activation="relu"))
model.add(Dense(32, activation="relu"))
model.add(Dense(1))
# 编译模型
model.compile(loss="mse", optimizer="adam", metrics=["mae"])
# 训练模型
model.fit(X_train, Y_train, epochs=80, batch_size=16, verbose=0)
# 使用测试资料评估模型
mse, mae = model.evaluate(X_test, Y_test)    
print("MSE_test: ", mse)
print("MAE_test: ", mae)

最后储存模型

# 存储Keras模型
model.save("bosidun.h5")

  • 6
    点赞
  • 72
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阡之尘埃

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值