仅供自己复习回顾使用,若有侵权可删除
前馈神经网络包含 3 种类型的神经元层。神经网络的起始端有一个输入层,输入层的每一个神经元包含一个观察值的某一个特征值。神经网络的末端有一个输出层,它把隐藏层的输出转换成对我们的任务有用的值。
有多个隐藏层的神经网络(比如 10 层、 100 层、 1000 层)被认为是很“深”的网络,它们的应用又被称为深度学习(deep learning).
一个观察值(更常见的情况是一组观察值的集合,又被称为批次(batch) 被传给神经网络,它的输出值就会被拿来用损失函数与观察值的真实值进行比较。这个过程叫作前向传播(forward propagation)。
接下来,算法“向后”在神经网络中传播,它识别出每个参数对预测值和真实值之间的差异的影响程度,这个过程叫作反向传播(backward propagation)。对于每一个参数,优化算法决定应该如何调整权重值才能改善输出值。
神经网络通过对训练集中的每个观察值重复做多次前向传播和反向传播(所有的观察值\都通过网络传递一次就被称为一个epoch。
Keras 是一个高层的软件包,使用了像 TensorFlow 和 Theano 这样的库来作为它的“引擎”。对于我们来说,Keras 的优势就在于它可以使我们专注于神经网络的设计和训练,把张量运算的细节留给其他库来完成。
为神经网络预处理数据
为什么要标准化:
- 一个神经网络的参数会被初始化(或者说被创建)为一些小的随机数。如果特征值比参数值大很多,神经网络往往表现得不如人意。
- 观察值的特征值经过这些神经元的传递后,会进行相加,所以让所有的特征值拥有同样的单位就很重要。
from sklearn import preprocessing
import numpy as np
features = np.array([[-100.1, 3240.1],[-200.2, -234.1],[5000.5, 150.1],
[6000.6, -125.1],[9000.9, -673.1]])
# 创建 scaler
scaler = preprocessing.StandardScaler() #均值为 0,标准差为 1
# 转换特征
features_standardized = scaler.fit_transform(features)
设计一个神经网络
隐藏层工作流程:
- 1.接收一些输入。
- 2.给每个输入乘以一个参数作为权重。
- 3.对所有加权过的输入求和,再加上偏差(一般是 1)。
- 4.接下来,将这个值应用到某个函数上(又叫作激活函数)。
- 5.把输出传递给下一层的神经元。
常用激活函数:
- 二元分类: sigmoid 激活函数
- 多元分类: softmax 激活函数
- 回归: 没有激活函数
常用损失函数:
- 二元分类: 二分交叉熵(Binary Cross-entropy)
- 多元分类: 分类交叉熵(Categorical cross-entropy)
- 回归: 均方误差
优化器
定义一个优化器,它可以被直观地理解为我们的策略“绕过了”损失函数,并且找到了产生最小误差的那些参数值。
常用的优化器有 :随机梯度下降、动量随机梯度下降、均方根传播和自适应矩估计
计算层数的时候,我们不会把输入层算在内,因为它没有任何参数需要学习
# 加载库
#from keras import models
from tensorflow.keras.models import Model
from keras import layers
# 启动神经网络
network = models.Sequential()
# 添加使用 ReLU 激活函数的全连接层
network.add(layers.Dense(units=16, activation="relu", input_shape=(10,)))
'''
这一层有 16 个神经元
神经网络的第一个隐藏层都必须包含一个 input_shape 参数,它表示特征数据的形状
'''
# 添加使用 ReLU 激活函数的全连接层
network.add(layers.Dense(units=16, activation="relu"))
'''
第二层和第一层一样,只不过不需要加上 input_shape 参数
'''
# 添加使用 sigmoid 激活函数的全连接层
network.add(layers.Dense(units=1, activation="sigmoid"))
'''
我们的神经网络是设计来做二元分类的,所以输出层仅包含一个带 sigmoid 激活函数的神经元,它将输出限制在 0 和 1 之间
'''
# 编译神经网络(我们想让网络如何学习)
network.compile(loss="binary_crossentropy", # 交叉熵(损失函数)
optimizer="rmsprop", # 均方根传播(优化算法)
metrics=["accuracy"]) # 将准确率作为性能指标(评估)
训练一个二元分类器
import numpy as np
from keras.datasets import imdb
from keras.preprocessing.text import Tokenizer
from keras import models
from keras import layers
np.random.seed(0)
number_of_features = 1000
# 从影评数据中加载数据和目标向量(5w影评)
(data_train, target_train), (data_test, target_test) = imdb.load_data(
num_words=number_of_features)
# 将影评数据转化为 one-hot 编码过的特征矩阵
tokenizer = Tokenizer(num_words=number_of_features)
features_train = tokenizer.sequences_to_matrix(data_train, mode="binary") #2.5W训练
features_test = tokenizer.sequences_to_matrix(data_test, mode="binary")
# 创建神经网络对象
network = models.Sequential()
# 添加使用 ReLU 激活函数的全连接层
network.add(layers.Dense(units=16, activation="relu",
input_shape=(number_of_features,)))
# 添加使用 ReLU 激活函数的全连接层
network.add(layers.Dense(units=16, activation="relu"))
# 添加使用 sigmoid 激活函数的全连接层
network.add(layers.Dense(units=1, activation="sigmoid"))
# 编译神经网络
network.compile(loss="binary_crossentropy", # 交叉熵
optimizer="rmsprop", # 均方根传播
metrics=["accuracy"]) # 将准确率作为性能指标
# 训练神经网络
history = network.fit(features_train, # 特征
target_train, # 目标向量
epochs=3, # epoch 的数量
verbose=1, # 每个 epoch 之后打印描述
batch_size=100, # 每个批次中观察值的数量
validation_data=(features_test, target_test)) # 测试数据
'''
epochs:神经网络通过对训练集中的每个观察值重复做多次前向传播和反向传播(所有的观察值都通过网络传递一次就被称为一个 epoch
verbose:0表示没有输出, 1 表示输出一个进度条, 2 表示每个 epoch 输出一条日志
batch_size 设定在计算多少个观察值之后才更新参数
或者,我们可以使用 validation_split 参数来设定要留多少比例的训练集数据用于评估模型。
'''
训练一个多元分类器
import numpy as np
from keras.datasets import reuters
from keras.utils.np_utils import to_categorical
from keras.preprocessing.text import Tokenizer
from keras import models
from keras import layers
np.random.seed(0)
# 设定我们想要的特征的数量
number_of_features = 5000
# 加载特征和目标数据
data = reuters.load_data(num_words=number_of_features)
(data_train, target_vector_train), (data_test, target_vector_test) = data
# 把特征数据转换成 one-hot 编码的特征矩阵
tokenizer = Tokenizer(num_words=number_of_features)
features_train = tokenizer.sequences_to_matrix(data_train, mode="binary")
features_test = tokenizer.sequences_to_matrix(data_test, mode="binary")
# 把 one-hot 编码的特征向量转换成特征矩阵
target_train = to_categorical(target_vector_train)
target_test = to_categorical(target_vector_test)
# 启动神经网络
network = models.Sequential()
# 添加使用 ReLU 激活函数的全连接层
network.add(layers.Dense(units=100,activation="relu",input_shape=(number_of_features,)))
# 添加使用 ReLU 激活函数的全连接层
network.add(layers.Dense(units=100, activation="relu"))
# 添加使用 softmax 激活函数的全连接层
network.add(layers.Dense(units=46, activation="softmax"))
# 编译神经网络
network.compile(loss="categorical_crossentropy", # 分类交叉熵
optimizer="rmsprop", # 均方根传播
metrics=["accuracy"]) # 将准确率作为性能指标
# 训练神经网络
history = network.fit(features_train, # 特征
target_train, # 目标向量
epochs=3, # 3 个 epoch
verbose=0, # 没有输出
batch_size=100, # 每个批次的观察值数量
validation_data=(features_test, target_test)) # 测试数据
训练一个回归模型
import numpy as np
from keras.preprocessing.text import Tokenizer
from keras import models
from keras import layers
from sklearn.datasets import make_regression
from sklearn.model_selection import train_test_split
from sklearn import preprocessing
np.random.seed(0)
# 生成特征矩阵和目标向量
features, target = make_regression(n_samples = 10000,n_features = 3,
n_informative = 3,n_targets = 1,noise = 0.0,random_state = 0)
# 把数据分为训练集和测试集
features_train, features_test, target_train, target_test = train_test_split(
features, target, test_size=0.33, random_state=0)
# 启动神经网络
network = models.Sequential()
# 添加使用 ReLU 激活函数的全连接层
network.add(layers.Dense(units=32,activation="relu",input_shape=(features_train.shape[1],)))
# 添加使用 ReLU 激活函数的全连接层
network.add(layers.Dense(units=32, activation="relu"))
# 添加没有激活函数的全连接层
network.add(layers.Dense(units=1))
# 编译神经网络
network.compile(loss="mse", # 均方误差
optimizer="RMSprop", # 优化算法
metrics=["mse"]) # 均方误差
# 训练神经网络
history = network.fit(features_train, # 特征
target_train, # 目标向量
epochs=10, # epoch 的数量
verbose=0, # 没有输出
batch_size=100, # 每个批次的观察值数量
validation_data=(features_test, target_test)) # 测试
做预测
训练后:
#预测测试集的分类
predicted_target = network.predict(features_test)
可视化训练历史
在很多情形下会有一个“甜蜜点”,到达这个点时,测试集误差(这是我们主要关注的误差)最小
import matplotlib.pyplot as plt
#训练神经网络
history = network.fit(...)
#######训练后########################
# 获取训练集和测试集的损失历史数值
training_loss = history.history["loss"]
test_loss = history.history["val_loss"]
# 为每个 epoch 创建编号
epoch_count = range(1, len(training_loss) + 1)
# 画出损失的历史数值
plt.plot(epoch_count, training_loss, "r--")
plt.plot(epoch_count, test_loss, "b-")
plt.legend(["Training Loss", "Test Loss"])
plt.xlabel("Epoch")
plt.ylabel("Loss")
plt.show()
# 获取训练集和测试集数据的准确率历史数值
training_accuracy = history.history["acc"]
test_accuracy = history.history["val_acc"]
plt.plot(epoch_count, training_accuracy, "r--")
plt.plot(epoch_count, test_accuracy, "b-")
# 可视化准确率的历史数值
plt.legend(["Training Accuracy", "Test Accuracy"])
plt.xlabel("Epoch")
plt.ylabel("Accuracy Score")
plt.show()
通过权重调节减少过拟合
在 Keras 中,我们可以通过在神经元层的参数中添加 kernel_regularizer=regularizers.l2(0.01) 来进行权重调节。其中, 0.01 表示要对参数值施加多重惩罚。
# 加载库
import numpy as np
from keras.datasets import imdb
from keras.preprocessing.text import Tokenizer
from keras import models
from keras import layers
from keras import regularizers
# 设置随机种子
np.random.seed(0)
# 设置我们想要的特征数量
number_of_features = 1000
# 从影评数据中加载数据和目标向量
(data_train, target_train), (data_test, target_test) = imdb.load_data(
num_words=number_of_features)
# 把影评数据转换为 one-hot 编码的特征矩阵
tokenizer = Tokenizer(num_words=number_of_features)
features_train = tokenizer.sequences_to_matrix(data_train, mode="binary")
features_test = tokenizer.sequences_to_matrix(data_test, mode="binary")
# 启动神经网络
network = models.Sequential()
# 添加使用 ReLU 激活函数的全连接层
network.add(layers.Dense(units=16,
activation="relu",
kernel_regularizer=regularizers.l2(0.01), #加惩罚项
input_shape=(number_of_features,)))
通过提前结束减少过拟合
'''
当测试集损失不再减少时就结束训练,这个策略被称为提前结束(early stopping) 我们加入了 EarlyStopping(monitor='val_loss', patience=2) ,告诉程序我们想监视每个 epoch 的测试集(验证集)损失,并且如果连续两个 epoch 测试集损失的情况都没有得到改善,就中断训练。
我们也可以添加一个ModelCheckpoint 操作,在每个检查点(如果你有一个持续多日的训练由于某种原因被打断,这时检查点就会很有用)之后把模型保存到文件中。这对我们会很有帮助,因为如果设定 save_best_only=True, ModelCheckpoint 就会仅保存最佳模型 '''
# 加载库
import numpy as np
from keras.datasets import imdb
from keras.preprocessing.text import Tokenizer
from keras import models
from keras import layers
from keras.callbacks import EarlyStopping, ModelCheckpoint
# 设置随机种子
np.random.seed(0)
# 设置我们想要的特征数量
number_of_features = 1000
# 从影评数据中加载数据和目标向量
(data_train, target_train), (data_test, target_test) = imdb.load_data(
num_words=number_of_features)
# 把影评数据转换为 one-hot 编码的特征矩阵
tokenizer = Tokenizer(num_words=number_of_features)
features_train = tokenizer.sequences_to_matrix(data_train, mode="binary")
features_test = tokenizer.sequences_to_matrix(data_test, mode="binary")
# 启动神经网络
network = models.Sequential()
# 添加使用 ReLU 激活函数的全连接层
network.add(layers.Dense(units=16,activation="relu",input_shape=(number_of_features,)))
# 添加使用 ReLU 激活函数的全连接层
network.add(layers.Dense(units=16, activation="relu"))
# 添加使用 sigmoid 激活函数的全连接层
network.add(layers.Dense(units=1, activation="sigmoid"))
# 编译神经网络
network.compile(loss="binary_crossentropy", # 交叉熵
optimizer="rmsprop", # 均方根传播
metrics=["accuracy"]) # 将准确率作为性能指标
# 设置一个回调函数来提前结束训练,并保存训练结束时的最佳模型!!!!!!!!
callbacks = [EarlyStopping(monitor="val_loss", patience=2),
ModelCheckpoint(filepath="best_model.h5",
monitor="val_loss", save_best_only=True)]
# 训练神经网络
history = network.fit(features_train, # 特征
target_train, # 目标向量
epochs=20, # epoch 的数量
callbacks=callbacks, # 提前结束
verbose=1, # 在每个 epoch 之后打印描述
batch_size=100, # 每个批次的观察值数量
validation_data=(features_test, target_test)) # 测试数据
通过 Dropout 减少过拟合
使用 Dropout(丢弃)方法向网络结构中引入噪声
在 Dropout 方法中,每创建一个批次的观察值用于训练时,一层或者多层的一部分神经元就会被乘以 0(即被丢弃)。虽然每个批次都是在同一个网络中训练的(比如,有同样的参数),但是每个批次面对的 网络结构都有些许差异。在隐藏层和输入层都可以添加 Dropout 方法。当一个输入层被丢弃后,它的特征值就不 会在那个批次中被传进网络。一般对神经元丢弃的比例为,输入层 0.2,隐藏层 0.5
import numpy as np
from keras.datasets import imdb
from keras.preprocessing.text import Tokenizer
from keras import models
from keras import layers
# 设置随机种子
np.random.seed(0)
# 设置我们想要的特征数量
number_of_features = 1000
# 从影评数据中加载数据和目标向量
(data_train, target_train), (data_test, target_test) = imdb.load_data(
num_words=number_of_features)
# 把影评数据转换为 one-hot 编码的特征矩阵
tokenizer = Tokenizer(num_words=number_of_features)
features_train = tokenizer.sequences_to_matrix(data_train, mode="binary")
features_test = tokenizer.sequences_to_matrix(data_test, mode="binary")
# 启动神经网络
network = models.Sequential()
# 为输入层添加一个 Dropout 层!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
network.add(layers.Dropout(0.2, input_shape=(number_of_features,)))
# 添加使用 ReLU 激活函数的全连接层
network.add(layers.Dense(units=16, activation="relu"))
# 为前面的隐藏层添加一个 Dropout 层!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
network.add(layers.Dropout(0.5))
# 添加使用 ReLU 激活函数的全连接层
network.add(layers.Dense(units=16, activation="relu"))
# 为前面的隐藏层添加一个 Dropout 层!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
network.add(layers.Dropout(0.5))
# 添加使用 sigmoid 激活函数的全连接层
network.add(layers.Dense(units=1, activation="sigmoid"))
# 编译神经网络
network.compile(loss="binary_crossentropy", # 交叉熵
optimizer="rmsprop", # 均方根传播
metrics=["accuracy"]) # 将准确率作为性能指标
# 训练神经网络
history = network.fit(features_train, # 特征
target_train, # 目标向量
epochs=3, # epoch 的数量
verbose=0, # 没有输出
batch_size=100, # 每个批次的观察值数量
validation_data=(features_test, target_test)) # 测试数据
保存模型训练过程
假设有一个神经网络需要花很长时间来训练,现在需要保存训练过程以防训练被中断ModelCheckpoint 会在每一个 epoch 之后保存模型,以避免这一类问题。具体来说,就是在每个 epoch 之后, ModelCheckpoint 把模型保存到 filepath 参数指定的路径中。\
如果只给定一个文件名(比如解决方案中的 models.hdf5),那么这个文件在每个 epoch 后都会被最近的模型重写。如果只想根据某个损失函数的表现来保存最佳模型,可以设置save_best_only=True 和 monitor='val_loss',这样如果现有模型比前一个模型的测试集损失更大的话,该文件并不会被重写。\
还有一种方案,我们可以保存每个 epoch 的模型,单独作为一个文件,并且将 epoch 编号和测试集损失值写在文件名中。比方说,设置 filepath 参数为 model_{epoch:02d}_{val_loss:.2f}.hdf5,如果在第 11 个 epoch 之后保存,测试集损失值是 0.33 的话,包含这个模型的文件的名字就是 model_10_0.33.hdf5(注意,这里 epoch 的编号是从 0 开始的)。
import numpy as np
from keras.datasets import imdb
from keras.preprocessing.text import Tokenizer
from keras import models
from keras import layers
from keras.callbacks import ModelCheckpoint
# 设定随机种子
np.random.seed(0)
# 设置我们想要的特征数量
number_of_features = 1000
# 从影评数据中加载数据和目标向量
(data_train, target_train), (data_test, target_test) = imdb.load_data(
num_words=number_of_features)
# 把影评数据转换为 one-hot 编码的特征矩阵
tokenizer = Tokenizer(num_words=number_of_features)
features_train = tokenizer.sequences_to_matrix(data_train, mode="binary")
features_test = tokenizer.sequences_to_matrix(data_test, mode="binary")
# 启动神经网络
network = models.Sequential()
# 添加使用 ReLU 激活函数的全连接层
network.add(layers.Dense(units=16,activation="relu",input_shape=(number_of_features,)))
# 添加使用 ReLU 激活函数的全连接层
network.add(layers.Dense(units=16, activation="relu"))
# 添加使用 sigmoid 激活函数的全连接层
network.add(layers.Dense(units=1, activation="sigmoid"))
# 编译神经网络
network.compile(loss="binary_crossentropy", # 交叉熵
optimizer="rmsprop", # 均方根传播
metrics=["accuracy"]) # 将准确率作为性能指标
# 设置一个回调函数来提前结束训练,并保存训练结束时的最佳模型!!!!!!!!!!!!!!!!!!!!!!!!!
checkpoint = [ModelCheckpoint(filepath="models.hdf5")]
# 训练神经网络
history = network.fit(features_train, # 特征
target_train, # 目标向量
epochs=3, # epoch 的数量
callbacks=checkpoint, # 检查点
verbose=0, # 没有输出
batch_size=100, # 每个批次的观察值数量
validation_data=(features_test, target_test)) # 测试数据
使用 k 折交叉验证评估神经网络
!!!!一般来说,没有必要使用 k 折交叉验证评估神经网络,也不推荐使用。
神经网络经常用于非常大的数据集而且可能需要几小时甚至几天来训练,所以如果训练时间很长的话,采用 k 折交叉验证就会增加计算开销,这并不是一个值得推荐的做法。
为了实现这一点,必须先创建一个函数,返回编译好的神经网络。接着,使用 KerasClassifier(这里假设有一个分类器,如果是回归分类器,就应该使用 KerasRegressor)来封装模型,使它可以被 scikit-learn 使用 '''
# 加载库
import numpy as np
from keras import models
from keras import layers
from keras.wrappers.scikit_learn import KerasClassifier
from sklearn.model_selection import cross_val_score
from sklearn.datasets import make_classification
# 设定随机种子
np.random.seed(0)
# 特征数量
number_of_features = 100
# 生成特征矩阵和目标向量
features, target = make_classification(n_samples = 10000,n_features = number_of_features,
n_informative = 3,n_redundant = 0,n_classes = 2,weights = [.5, .5],
random_state = 0)
# 创建一个函数,返回编译过的网络
def create_network():
# 启动神经网络
network = models.Sequential()
# 添加使用 ReLU 激活函数的全连接层
network.add(layers.Dense(units=16, activation="relu", input_shape=(
number_of_features,)))
# 添加使用 ReLU 激活函数的全连接层
network.add(layers.Dense(units=16, activation="relu"))
# 添加使用 sigmoid 激活函数的全连接层
network.add(layers.Dense(units=1, activation="sigmoid"))
# 编译神经网络
network.compile(loss="binary_crossentropy", # 交叉熵
optimizer="rmsprop", # 均方根传播
metrics=["accuracy"]) # 将准确率作为性能指标
# 返回编译过的网络
return network
# 封装 Keras 模型,以便它能被 scikit-learn 使用
neural_network = KerasClassifier(build_fn=create_network,
epochs=10,
batch_size=100,
verbose=0)
# 使用 3 折交叉验证来评估神经网络
cross_val_score(neural_network, features, target, cv=3)
调校神经网络
我们对一些超参数选项(包括优化算法、 epoch 的数量和批次的大小)实施了交叉验证的网格搜索
# 加载库
import numpy as np
from keras import models
from keras import layers
from keras.wrappers.scikit_learn import KerasClassifier
from sklearn.model_selection import GridSearchCV
from sklearn.datasets import make_classification
# 设置随机种子
np.random.seed(0)
# 特征的数量
number_of_features = 100
# 生成特征矩阵和目标向量
features, target = make_classification(n_samples = 10000,n_features = number_of_features,
n_informative = 3,n_redundant = 0,n_classes = 2,weights = [.5, .5],
random_state = 0)
# 创建一个函数,返回编译过的神经网络
def create_network(optimizer="rmsprop"):
# 启动神经网络
network = models.Sequential()
# 添加使用 ReLU 激活函数的全连接层
network.add(layers.Dense(units=16,
activation="relu",
input_shape=(number_of_features,)))
# 添加使用 ReLU 激活函数的全连接层
network.add(layers.Dense(units=16, activation="relu"))
# 添加使用 sigmoid 激活函数的全连接层
network.add(layers.Dense(units=1, activation="sigmoid"))
# 编译神经网络
network.compile(loss="binary_crossentropy", # 交叉熵
optimizer=optimizer, # 优化器
metrics=["accuracy"]) # 将准确率作为性能指标
# 返回编译过的网络
return network
# 封装 Keras 模型以便它能被 scikit-learn 使用
neural_network = KerasClassifier(build_fn=create_network, verbose=0)
# 创建超参数空间
epochs = [5, 10]
batches = [5, 10, 100]
optimizers = ["rmsprop", "adam"]
# 创建超参数选项
hyperparameters = dict(optimizer=optimizers, epochs=epochs, batch_size=batches)
# 创建网格搜索
grid = GridSearchCV(estimator=neural_network, param_grid=hyperparameters)
# 实现网格搜索
grid_result = grid.fit(features, target)
# 查看最优神经网络的超参数
grid_result.best_params_
可视化神经网络
如果想在 Jupyter Notebook 中显示一个神经网络,可以使用 model_to_dot。 show_shapes 参数指定是否展示输入和输出的形状,它可以帮助我们调试网络。如果想展示一个更简单的模型,可以设置 show_shapes=False
# 加载库
from keras import models
from keras import layers
from IPython.display import SVG
from keras.utils.vis_utils import model_to_dot
from keras.utils import plot_model
# 启动神经网络
network = models.Sequential()
# 添加使用 ReLU 激活函数的全连接层
network.add(layers.Dense(units=16, activation="relu", input_shape=(10,)))
# 添加使用 ReLU 激活函数的全连接层
network.add(layers.Dense(units=16, activation="relu"))
# 添加使用 sigmoid 激活函数的全连接层
network.add(layers.Dense(units=1, activation="sigmoid"))
# 可视化网络结构
SVG(model_to_dot(network, show_shapes=True).create(prog="dot", format="svg"))
# 将可视化后的网络结构图保存为文件
plot_model(network, show_shapes=True, to_file="network.png")
图像分类
前馈网络的缺点:
- 首先,
前馈神经网络并没有考虑像素之间的空间结构。比如对于一张 10× 10 像素的图像,我们可能会把它转换成一个有 100 个像素特征的向量,这样的话在前向传播时,就会认为第 1 个特征(比如像素值)和第 10 个特征之间的空间关系与它和第 11 个特征之间的空间关系是一样的。但事实上第 10 个特征代表的是处在图片远端的像素,距离第 1 个特征代表的像素较远,而第 11 个特征表示的是第 1 个像素正下方的像素。\ - 其次,
前馈神经网络学习的是特征的全局关系而不是局部的模式。更具体地说,这意味着前馈神经网络无法识别一个物体,不管该物体出现在图像的何处。举例来说,假设我们要训练一个神经网络来识别脸,而这些脸可能出现在图像的任意地方,从右上方到中间再到左下方。
卷积神经网络(Convolutional Neural Networks,又被简写为 ConvNets)是一种流行的神经网络,而且被证明在计算机视觉领域非常有效。
- 在卷积神经网络中,卷积可以被想象成在图像的像素上滑动一个窗口,通过这个窗口查看像素和它周围的邻居们。接着,它把初始图像数据转换为一个新的 3维张量,头两个张量是近似的宽度和高度,而第 3 个维度(包含颜色值)现在表示像素“属于”哪种模式(比如,尖角或者梯度渐变,它也被叫作过滤器)。
- 第二个重要的概念是池化层。池化层会在我们的数据上移动一个窗口(通常窗口是按每n 个像素作为一个步长来移动的,叫作 striding),然后对窗口里的数据以某种方式求和,以缩减数据规模。最常用的方法是最大池化(max pooling),它把每个窗口的最大值传递到下一层。使用最大池化的原因之一是它很实用,卷积过程产生了很多要学习的参数,这会让学习过程很快就没有什么收获,所以通过最大池化减少参数的数量是有益的。可以直观地将最大池化想象成“缩小”图像。
import numpy as np
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten
from keras.layers.convolutional import Conv2D, MaxPooling2D
from keras.utils import np_utils
from keras import backend as K
# 设置色彩通道值优先
K.set_image_data_format("channels_first")
# 设置随机种子
np.random.seed(0)
# 图像信息
channels = 1
height = 28
width = 28
# 从 MNIST 数据集中读取数据和目标
(data_train, target_train), (data_test, target_test) = mnist.load_data()
# 将训练集图像数据转换成特征
data_train = data_train.reshape(data_train.shape[0], channels, height, width)
# 将测试集图像数据转换成特征
data_test = data_test.reshape(data_test.shape[0], channels, height, width)
# 将像素的强度值收缩到 0 和 1 之间
features_train = data_train / 255
features_test = data_test / 255
# 对目标进行 one-hot 编码
target_train = np_utils.to_categorical(target_train)
target_test = np_utils.to_categorical(target_test)
number_of_classes = target_test.shape[1]
# 启动神经网络
network = Sequential()
# 添加有 64 个过滤器、一个大小为 5x5 的窗口和 ReLU 激活函数的卷积层
network.add(Conv2D(filters=64,kernel_size=(5, 5),
input_shape=(channels, width,height),activation='relu'))
# 添加带一个 2x2 窗口的最大池化层
network.add(MaxPooling2D(pool_size=(2, 2)))
# 添加 Dropout 层
network.add(Dropout(0.5))
# 添加一层来压平输入
network.add(Flatten())
# 添加带 ReLU 激活函数的有 128 个神经元的全连接层
network.add(Dense(128, activation="relu"))
# 添加 Dropout 层
network.add(Dropout(0.5))
# 添加使用 softmax 激活函数的全连接层
network.add(Dense(number_of_classes, activation="softmax"))
# 编译神经网络
network.compile(loss="categorical_crossentropy", # 交叉熵
optimizer="rmsprop", # 均方根传播
metrics=["accuracy"]) # 将准确率作为性能指标
# 训练神经网络
network.fit(features_train, # 特征
target_train, # 目标向量
epochs=2, # epoch 的数量
verbose=0, # 没有输出
batch_size=1000, # 每个批次的观察值数量
validation_data=(features_test, target_test)) # 测试数据
通过图像增强来改善卷积神经网络的性能
为了得到更好的结果,对图像进行预处理,并使用 ImageDataGenerator 提前增强数据
# 加载库
from keras.preprocessing.image import ImageDataGenerator
# 创建图像增强对象
augmentation = ImageDataGenerator(featurewise_center=True, # 实施 ZCA 白化
zoom_range=0.3, # 随机放大图像
width_shift_range=0.2, # 随机打乱图像
horizontal_flip=True, # 随机翻转图像
rotation_range=90) # 随机旋转图像
'''
featurewise_center=True 来标准化整个数据集
第二个改善卷积神经网络性能的技术是加入噪声。
可以通过多种方法随机转换图像,以实现向样本数据中加入噪声,比如镜像翻转图像,或者局部放大图像。即使很小的变化,也可以显著改善模型的性能
'''
# 对 raw/images 文件夹下所有的图像进行处理
augment_images = augmentation.flow_from_directory("raw/images", # 图像文件夹
batch_size=32, # 批次的大小
class_mode="binary", # 分类
save_to_dir="processed images")
# 训练神经网络
network.fit_generator(augment_images,
# 在每个 epoch 中调用生成器的次数
steps_per_epoch=2000,
# epoch 的数量
epochs=5,
# 测试数据生成器
validation_data=augment_images_test,
# 在每个测试 epoch 中调用生成器的次数
validation_steps=800)
文本分类
使用长短期记忆递归神经网络:
递归神经网络有一个关键特性,即信息在网络中回环,这让递归神经网络拥有一种记忆,使它可以更好地理解顺序数据。
import numpy as np
from keras.datasets import imdb
from keras.preprocessing import sequence
from keras import models
from keras import layers
# 设置随机种子
np.random.seed(0)
# 设置想要的特征数量
number_of_features = 1000
# 从影评数据中加载数据和目标向量
(data_train, target_train), (data_test, target_test) = imdb.load_data(
num_words=number_of_features)
# 采用添加填充值或者截断的方式,使每个样本都有 400 个特征
features_train = sequence.pad_sequences(data_train, maxlen=400)
features_test = sequence.pad_sequences(data_test, maxlen=400)
# 启动神经网络
network = models.Sequential()
# 添加嵌入层
network.add(layers.Embedding(input_dim=number_of_features, output_dim=128))
#对于每一个传入 Embedding 层的值, Keras 都会输出一个向量来表示这个词
# 添加一个有 128 个神经元的长短期记忆网络层
network.add(layers.LSTM(units=128))
# 添加使用 sigmoid 激活函数的全连接层
network.add(layers.Dense(units=1, activation="sigmoid"))
# 编译神经网络
network.compile(loss="binary_crossentropy", # 交叉熵
optimizer="Adam", # Adam 优化器
metrics=["accuracy"]) # 将准确率作为性能指标
# 训练神经网络
history = network.fit(features_train, # 特征
target_train, # 目标向量
epochs=3, # epoch 的数量
verbose=0, # 没有输出
batch_size=1000, # 每个批次的样本数量
validation_data=(features_test, target_test)) # 测试数据