《机器学习实战:基于Scikit-Learn、Keras和Ten
2019-10-17 本文已影响0人
SeanCheney
电脑上看效果好,不用左右滑屏。都调好了,复制粘贴就可以在PyCharm里直接跑起来。
# -*- coding: utf-8 -*-
# 需要安装和引入的包有tensorflow\pandas\numpy\matplotlib\scikit-learn
# 使用pip安装:pip install -i https://pypi.tuna.tsinghua.edu.cn/simple/ tensorflow pandas matplotlib scikit-learn
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from tensorflow import keras
# 加载Fashion MNIST数据集,格式与MNIST完全相同(70000张灰度图,每张的像素是28 × 28,
# 共有10类),图的内容是流行物品,每类中的图片更丰富,# 识图的挑战性比MNIST高得多。
fashion_mnist = keras.datasets.fashion_mnist
(X_train_full, y_train_full), (X_test, y_test) = fashion_mnist.load_data()
# 训练集的形状和类型
print('训练集的形状:60000张图片,像素是28×28', X_train_full.shape)
print('训练集的数据类型', X_train_full.dtype)
# 该数据集已经分成了训练集和测试集,但没有验证集。所以要建一个验证集,另外,因为要用梯度下
# 降训练神经网络,必须要对输入特征进行缩放。简单起见,通过除以255.0将强度范围变为0-1:
X_valid, X_train = X_train_full[:5000] / 255.0, X_train_full[5000:] / 255.0
y_valid, y_train = y_train_full[:5000], y_train_full[5000:]
# Fashion MNIST的分类名列表:
class_names = ["T-shirt/top", "Trouser", "Pullover", "Dress", "Coat",
"Sandal", "Shirt", "Sneaker", "Bag", "Ankle boot"]
# 训练集的第一个y值是4,所以属于Coat
print('训练集的第一个y值是4,所以属于:', class_names[y_train[0]])
# 创建一个Sequential模型,这是Keras最简单的模型,是由单层神经元顺序连起来的,被称为Sequential API
model = keras.models.Sequential()
# 接下来创建了第一层,这是一个Flatten层,它的作用是将每个输入图片转变为1D数组:如果输入数据是矩阵X,
# 该层则计算X.reshape(-1, 1)。该层没有任何参数,只是做一些简单预处理。因为是模型的第一层,必须要指
# 明input_shape,input_shape不包括批次大小,只是实例的形状。
model.add(keras.layers.Flatten(input_shape=[28, 28]))
# 添加一个有300个神经元的紧密层,激活函数是ReLU。每个紧密层只负责自身的权重矩阵,权重矩阵是神经元与输
# 入的所有连接权重。紧密层还要负责偏置项
# (每个神经元都有一个偏置项)矢量。
model.add(keras.layers.Dense(300, activation="relu"))
# 再添加第二个紧密层,激活函数仍然是ReLU
model.add(keras.layers.Dense(100, activation="relu"))
# 最后,加上一个拥有10个神经元的输出层(每有一个类就要有一个神经元),激活函数是softmax(保证输出的
# 概率和等于1,因为就只有这十个类,具有排他性)
model.add(keras.layers.Dense(10, activation="softmax"))
# 除了一层一层加层,也可以传递一个层组成的列表:
# model = keras.models.Sequential([
# keras.layers.Flatten(input_shape=[28, 28]),
# keras.layers.Dense(300, activation="relu"),
# keras.layers.Dense(100, activation="relu"),
# keras.layers.Dense(10, activation="softmax")
# ])
# 模型的summary()方法可以展示所有层,包括每个层的名字(名字是自动生成的,除非建层时指定名字),输出
# 的形状(None代表批次大小可以是任意值),和参数的数量。
print(model.summary())
# 获取所有的层
print(model.layers)
# 每个层的名字
print([layer.name for layer in model.layers])
# 可以用get_weights()和set_weights()方法,获取神经层的所有参数。对于紧密层,参数包括连接权重和
# 偏置项:
hidden1 = model.layers[1]
weights, biases = hidden1.get_weights()
print(weights)
print(weights.shape)
print(biases)
print(biases.shape)
# 编译模型
# 首先,因为使用的是稀疏标签(每个实例只有一个目标类的索引,在这个例子中,目标类索引是0到9),且就
# 是这十个类,没有其它的,所以使用的是"sparse_categorical_crossentropy"损失函数。如果每个实例
# 的每个类都有一个目标概率(比如独热矢量,[0., 0., 0., 1., 0., 0., 0., 0., 0., 0.],来表示类3),
# 则就要使用"categorical_crossentropy"损失函数。如果是做二元分类(有一个或多个二元标签),输出层
# 就得使用"sigmoid"激活函数,损失函数则变为"binary_crossentropy"。对于优化器,"sgd"表示使用随机
# 梯度下降训练模型。换句话说,Keras会进行反向传播算法。最后,因为是个分类器,最好在训练和评估时测量
# "accuracy"。
model.compile(loss="sparse_categorical_crossentropy",
optimizer="sgd",
metrics=["accuracy"])
# 训练模型
# 向fit()方法传递了输入特征(X_train)和目标类(y_train),还要要训练的周期数(不设置的话,默认的周期
# 数是1,肯定是不能收敛到一个好的解的)。另外还传递了验证集(它是可选的)。Keras会在每个周期结束后,
# 测量损失和指标,这样就可以监测模型的表现。如果模型在训练集上的表现优于在验证集上的表现,可能模型在训
# 练集上就过拟合了(或者就是存在bug,比如训练集和验证集的数据不匹配)。为节省时间,周期数设成10
history = model.fit(X_train, y_train, epochs=10, validation_data=(X_valid, y_valid))
# 画学习曲线
# fit()方法会返回History对象,包含:训练参数(history.params)、周期列表(history.epoch)、以及
# 最重要的包含训练集和验证集的每个周期后的损失和指标的字典(history.history)。如果用这个字典创建一个
# pandas的DataFrame,然后使用方法plot(),就可以画出学习曲线
pd.DataFrame(history.history).plot(figsize=(8, 5))
plt.grid(True)
plt.gca().set_ylim(0, 1) # 纵坐标的范围设为0-1
plt.show()
# 用测试集评估泛化误差。只需使用evaluate()方法
print(model.evaluate(X_test, y_test))
# 使用模型进行预测
X_new = X_test[:3]
y_proba = model.predict(X_new)
print(y_proba.round(2))
# 我得到的结果是,输出的是概率值:
# [[0. 0. 0. 0. 0. 0. 0. 0. 0. 1.]
# [0. 0. 1. 0. 0. 0. 0. 0. 0. 0.]
# [0. 1. 0. 0. 0. 0. 0. 0. 0. 0.]]
# 输出的是类别名
y_pred = model.predict_classes(X_new)
print(np.array(class_names)[y_pred])
# 使用Sequential API搭建回归MLP
from sklearn.datasets import fetch_california_housing
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
# 获取数据
housing = fetch_california_housing()
# 切分数据集
X_train_full, X_test, y_train_full, y_test = train_test_split(
housing.data, housing.target)
X_train, X_valid, y_train, y_valid = train_test_split(
X_train_full, y_train_full)
# 做特征缩放
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_valid = scaler.transform(X_valid)
X_test = scaler.transform(X_test)
# 使用Sequential API搭建、训练、评估和使用回归MLP做预测,和前面的分类MLP很像。区别在于输出层只有
# 一个神经元(因为只想预测一个值而已),也没有使用激活函数,损失函数是均方误差。因为数据集有噪音,我
# 们就是用一个隐藏层,并且神经元也比之前少,以避免过拟合:
model = keras.models.Sequential([
keras.layers.Dense(30, activation="relu", input_shape=X_train.shape[1:]),
keras.layers.Dense(1)
])
# 编译
model.compile(loss="mean_squared_error", optimizer="sgd")
# 训练
history = model.fit(X_train, y_train, epochs=20,
validation_data=(X_valid, y_valid))
# 评估
mse_test = model.evaluate(X_test, y_test)
# 预测
X_new = X_test[:3] # pretend these are new instances
y_pred = model.predict(X_new)
print(y_pred)
# 保存模型
# model = keras.layers.Sequential([...]) # or keras.Model([...])
# model.compile([...])
# model.fit([...])
# model.save("my_keras_model.h5")
# 加载模型
# model = keras.models.load_model("my_keras_model.h5")
# 使用调回创建检查点
# fit()方法接受参数callbacks,可以让用户指明一个Keras列表,让Keras在训练开始和结束、每个周期开
# 始和结束、甚至是每个批次的前后调用。例如,ModelCheckpoint可以在每个时间间隔保存检查点,默认是
# 每个周期结束之后:
# [...] # 搭建编译模型
# checkpoint_cb = keras.callbacks.ModelCheckpoint("my_keras_model.h5")
# history = model.fit(X_train, y_train, epochs=10, callbacks=[checkpoint_cb])
# 早停的两种方法
# 另外,如果训练时使用了验证集,可以在创建检查点时设定save_best_only=True,只有当模型在验证集上
# 取得最优值时才保存模型。这么做可以不必担心训练时间过长和训练集过拟合:只需加载训练好的模型,就能保
# 证是在验证集上表现最好的模型。
# checkpoint_cb = keras.callbacks.ModelCheckpoint("my_keras_model.h5",
# save_best_only=True)
# history = model.fit(X_train, y_train, epochs=10,
# validation_data=(X_valid, y_valid),
# callbacks=[checkpoint_cb])
# model = keras.models.load_model("my_keras_model.h5") # 滚回到最优模型
# 另一种实现早停的方法是使用EarlyStopping调回。当检测到经过几个周期(周期数由参数patience确定),
# 验证集表现没有提升时,就会中断训练,还能自动滚回到最优模型。可以将保存检查点(避免宕机)和早停
# (避免浪费时间和资源)结合起来:
# early_stopping_cb = keras.callbacks.EarlyStopping(patience=10,
# restore_best_weights=True)
# history = model.fit(X_train, y_train, epochs=100,
# validation_data=(X_valid, y_valid),
# callbacks=[checkpoint_cb, early_stopping_cb])