一、概念
1. 多层感知机:MLP(Multilayer Perceptron)
人工神经网络领域通常被称为神经网络或多层感知机,可能是最有用的神经网络类型。
感知机是单个神经元模型,用以组成复杂神经网络。它于1958年由Frank Rosenblatt第一次引入。单层感知器可以用来区分线性可分的数据,并且一定可以在有限的迭代次数中收敛。
2. 单层感知器示例
3. 多层感知机除了输入与输出层,中间可以有多个隐层,其中最简单的MLP只含一个隐层,即三层的结构,:
多层感知机层与层之间是全连接的。
4. 激活函数
隐藏层与输入层是全连接的,假设输入层用向量X表示,则隐藏层的输出就是 f (W1X+b1),W1是权重(也叫连接系数),b1是偏置,
函数f 可以是常用的sigmoid函数或者tanh函数(激活函数)。激活函数,是为了让神经元引入非线性因素,使神经网络可以任意逼近任何非线性函数。
激活函数需要具备以下几点性质:
- 连续并可导(允许少数点上不可导)的非线性函数。可导的激活函数可以直接利用数值优化的方法来学习网络参 数。
- 激活函数及其导函数要尽可能的简单,有利于提高网络计算效率。
- 激活函数的导函数的值域要在一个合适的区间内,不能太大也不能太小,否则会影响训练的效率和稳定性。
常用的激活函数有sigmod、Tanh等。
二、keras的模型和层
下面使用模型类的编写一个线性模型: y_pred = a * X + b:
import tensorflow as tf
X = tf.constant([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
y = tf.constant([[10.0], [20.0]])
# 定义一个模型
# 继承 tf.keras.Model 后,就同时可以使用父类的若干方法和属性
class Linear(tf.keras.Model):
# 模型初始化
def __init__(self):
super().__init__()
self.dense = tf.keras.layers.Dense(
units=1,
activation=None,
kernel_initializer=tf.zeros_initializer(),
bias_initializer=tf.zeros_initializer()
)
# 模型调用
def call(self, input):
output = self.dense(input)
return output
# 实例化类
model = Linear()
optimizer = tf.keras.optimizers.SGD(learning_rate=0.01)
for i in range(100):
with tf.GradientTape() as tape:
# 调用模型 y_pred = model(X) 而不是显式写出 y_pred = a * X + b
y_pred = model(X)
# 均方误差损失函数
loss = tf.reduce_mean(tf.square(y_pred - y))
# 使用 model.variables 这一属性直接获得模型中的所有变量
grads = tape.gradient(loss, model.variables)
optimizer.apply_gradients(grads_and_vars=zip(grads, model.variables))
print(model.variables)
- 上面全连接层 tf.keras.layers.Dense 封装了 output = activation(tf.matmul(input, kernel) + bias) 这一线性变换 + 激活函数的计算操作
- kernel 和 bias 是层中可训练的变量。
假设输入张量的形状为 input = [batch_size, input_dim] ,经过全连接层,输出张量的形状为 [batch_size, units] 的二维张量。
三、多层感知机
主要分为4个步骤:
- 获取数据集: tf.keras.datasets
- 构建模型:tf.keras.Model 和 tf.keras.layers
- 训练模型:tf.keras.losses 计算损失函数,并使用 tf.keras.optimizer 优化模型
- 评估模型:tf.keras.metrics 计算评估指标
下面示例数据还是mnist数字手写体。
1. 加载数据
import tensorflow as tf
import numpy as np
class MNISTLoader():
def __init__(self):
mnist = tf.keras.datasets.mnist
(self.train_data, self.train_label), (self.test_data, self.test_label) = mnist.load_data()
# MNIST中的图像默认为uint8(0-255的数字)
# 以下代码将其归一化到0-1之间的浮点数,并在最后增加一维作为颜色通道
self.train_data = np.expand_dims(
self.train_data.astype(
np.float32) / 255.0,
axis=-1) # [60000, 28, 28, 1]
self.test_data = np.expand_dims(
self.test_data.astype(
np.float32) / 255.0,
axis=-1) # [10000, 28, 28, 1]
self.train_label = self.train_label.astype(np.int32) # [60000]
self.test_label = self.test_label.astype(np.int32) # [10000]
self.num_train_data, self.num_test_data = self.train_data.shape[0], self.test_data.shape[0]
def get_batch(self, batch_size):
# 从数据集中随机取出batch_size个元素并返回
index = np.random.randint(0, np.shape(self.train_data)[0], batch_size)
return self.train_data[index, :], self.train_label[index]
2. 构建模型
class MLP(tf.keras.Model):
def __init__(self):
super().__init__()
# Flatten层将除第一维(batch_size)以外的维度展平
self.flatten = tf.keras.layers.Flatten()
# 全连接层
self.dense1 = tf.keras.layers.Dense(units=100, activation=tf.nn.relu)
self.dense2 = tf.keras.layers.Dense(units=10)
def call(self, inputs): # [batch_size, 28, 28, 1]
x = self.flatten(inputs) # [batch_size, 784]
x = self.dense1(x) # [batch_size, 100]
x = self.dense2(x) # [batch_size, 10]
output = tf.nn.softmax(x)
return output
3. 模型训练
num_epochs = 5 # 训练轮数
batch_size = 50 # 批大小
learning_rate = 0.001 # 学习率
model = MLP() # 实例化模型
data_loader = MNISTLoader() # 数据载入
optimizer = tf.keras.optimizers.Adam(learning_rate=learning_rate)
num_batches = int(data_loader.num_train_data // batch_size * num_epochs)
for batch_index in range(num_batches):
# 随机取一批训练数据
X, y = data_loader.get_batch(batch_size)
with tf.GradientTape() as tape:
# 计算模型预测值
y_pred = model(X)
# 计算损失函数
loss = tf.keras.losses.sparse_categorical_crossentropy(y_true=y, y_pred=y_pred)
loss = tf.reduce_mean(loss)
print("batch %d: loss %f" % (batch_index, loss.numpy()))
# 计算模型变量的导数
grads = tape.gradient(loss, model.variables)
# 优化器更新模型参数以减小损失函数
optimizer.apply_gradients(grads_and_vars=zip(grads, model.variables))
4. 评估模型
# 评估器
sparse_categorical_accuracy = tf.keras.metrics.SparseCategoricalAccuracy()
# 迭代轮数
num_batches = int(data_loader.num_test_data // batch_size)
for batch_index in range(num_batches):
start_index, end_index = batch_index * batch_size, (batch_index + 1) * batch_size
# 模型预测的结果
y_pred = model.predict(data_loader.test_data[start_index: end_index])
sparse_categorical_accuracy.update_state(
y_true=data_loader.test_label[start_index: end_index], y_pred=y_pred)
print("test accuracy: %f" % sparse_categorical_accuracy.result())