首先是处理训练数据。导入或者随机定义训练的数据 和 ,这里我们使用 NumPy 随机定义训练的数据:
import numpy as np
import tensorflow as tf
x_data = np.linspace(-1, 1, 300)[:, np.newaxis] # 生成 x
noise = np.random.normal(0, 0.05, x_data.shape) # 生成 noise
y_data = np.square(x_data) - 0.5 + noise # 生成 y
x_data = x_data.reshape([-1, 1]) # 将 x 转换为维度为 (300, 1) 的矩阵
接下来,需要定义神经层,我们定义一个使用 relu 激活函数的全连接层。自定义层需要继承·tf.keras.layers.Layer
类,并重写 _init_() 、 build() 和 call() 三个方法。
class LinearLayer(tf.keras.layers.Layer): # 继承 tf.keras.layers.Layer 类
def __init__(self, units): # units 是输出张量的维度
super().__init__()
self.units = units
def build(self, input_shape):
self.w = self.add_weight(name='w',
shape=[input_shape[-1], self.units], initializer=tf.zeros_initializer()) # 权重 w,初始化为 0,shape 为 [input_shape[-1], units]
self.b = self.add_weight(name='b',
shape=[self.units], initializer=tf.zeros_initializer()) # 偏置 b,初始化为 0,shape 为 [units]
def call(self, inputs):
y_pred = tf.nn.relu(tf.matmul(inputs,self.w) + self.b) # y = relu(x * w + b)
return y_pred
接下来,需要定义模型,我们要定义一个两层神经网络,模型包含一个隐藏层和一个输出层。我们可以通过继承tf.keras.Model
来定义自己的模型,并需要重写 _init_() (构造函数,初始化)和 call(input) (模型调用)两个方法
class MyModel(tf.keras.Model): # 继承 tf.keras.Model 类
def __init__(self):
super().__init__()
self.layer1 = LinearLayer(units=10) # 自定义的全连接层
self.layer2 = tf.keras.layers.Dense(units=1) # tensorflow 的 Dense 层
def call(self, inputs):
x = self.layer1(inputs) # 添加隐藏层
output = self.layer2(x) # 添加输出层
return output
实例化我们定义的模型,并且设置优化器:
model = MyModel() # 实例化模型
optimizer = tf.keras.optimizers.Adam(learning_rate=0.1) # 设置优化器为 Adam 优化器,学习率为 0.1
开始训练:
from sklearn.utils import shuffle
epoches = 10 # 设置迭代次数
for epoch in range(epoches):
trainX, trainY =x_data[0:250], y_data[0:250] # 取前 250 个数据为训练集
with tf.GradientTape() as tape: # 自动求导记录器
y_pred = model(trainX)
loss = tf.reduce_mean(tf.square(y_pred - trainY)) # 使用均方损失
grads = tape.gradient(loss, model.variables) # 使用 model.variables 这一属性直接获得模型中的所有变量
optimizer.apply_gradients(grads_and_vars=zip(grads, model.variables))
testX, testY = x_data[250:300], y_data[250:300] # 取后 50 个数据为训练集
y_pred_test = model(testX)
loss_test = tf.reduce_mean(tf.square(y_pred_test - testY))
x_data, y_data = shuffle(x_data, y_data) # 打乱数据
我们在模型函数里加上 Dropout
防止过拟合:
class MyModelDrop(tf.keras.Model):
def __init__(self):
super().__init__()
self.layer1 = LinearLayer(units=10)
self.layer2 = tf.keras.layers.Dropout(rate=0.5) # 添加 Dropout,参数 rate 用于指定 drop 的比例
# 隐含节点 dropout 率等于 0.5 的时候效果最好,即 rate = 0.5,
# 原因是 0.5 的时候 dropout 随机生成的网络结构最多。
self.layer3 = tf.keras.layers.Dense(units=1)
def call(self, inputs):
x = self.layer1(inputs)
x = self.layer2(x)
output = self.layer3(x)
return output
同样我们可以运行添加了 Dropout 的模型:
model = MyModelDrop() # 实例化模型
optimizer = tf.keras.optimizers.Adam(learning_rate=0.1)
epoches = 10
for epoch in range(epoches):
trainX, trainY =x_data[0:250], y_data[0:250]
with tf.GradientTape() as tape:
y_pred = model(trainX)
loss = tf.reduce_mean(tf.square(y_pred - trainY))
grads = tape.gradient(loss, model.variables)
optimizer.apply_gradients(grads_and_vars=zip(grads, model.variables))
testX, testY = x_data[250:300], y_data[250:300]
y_pred_test = model(testX)
loss_test = tf.reduce_mean(tf.square(y_pred_test - testY))
x_data, y_data = shuffle(x_data, y_data)
由于数据和网络比较简单,所以加了 dropout 后效果差别不大。
有了神经网络,我们就可以对输入的信息进行特征提取,但是图像包含的信息量巨大,一般的神经网络并不能准确的提取图像的特征,这时候就要用到卷积神经网络。
首先是数据预处理过程,我们使用 scikit-learn 提供的数据集,并完成形状处理:
from sklearn.datasets import load_digits # sklearn 为我们提供的手写数字数据集
# 数据预处理
digits = load_digits()
X_data = digits.data.astype(np.float32)
y_data = digits.target.astype(np.float32).reshape(-1, 1)
X_data.shape, y_data.shape
接下来,对数据进行标准化处理,可以提升模型的训练效果:
# 数据的标准化(normalization)是将数据按比例缩放,
# 使之落入一个小的特定区间。这样去除数据的单位限制,
# 将其转化为无量纲的纯数值,便于不同单位或量级的指标能够进行比较和加权。
from sklearn.preprocessing import OneHotEncoder
from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler()
X = scaler.fit_transform(X_data)
X = X.reshape(-1, 8, 8, 1)
y = OneHotEncoder(categories='auto').fit_transform(
y_data).todense() # one-hot 编码
X.shape, y.shape
用 Keras 的 Sequential API 来构建模型:
model = tf.keras.models.Sequential()
model.add(tf.keras.layers.Conv2D(
filters=10, # 卷积层神经元(卷积核)数目
kernel_size=[3, 3], # 卷积核大小
strides=(1, 1), # 步长
padding='same', # padding策略(vaild 或 same)
activation=tf.nn.relu, # 激活函数
input_shape=(8, 8, 1) # 指出输入的形状 (samples,rows,cols,channels),只指出后三维,第一维度按 batch_size 自动指定
))
model.add(tf.keras.layers.MaxPool2D(
pool_size=[3, 3], # 池窗口大小
strides=2, # 步长
padding='same'
))
model.add(tf.keras.layers.Conv2D(filters=5, kernel_size=[3, 3], strides=(2, 2), padding='same'))
model.add(tf.keras.layers.BatchNormalization())
model.add(tf.keras.layers.Activation('relu'))
model.add(tf.keras.layers.MaxPool2D(pool_size=[3, 3], strides=2, padding='same'))
model.add(tf.keras.layers.Reshape(target_shape=(1*1*5,)))
model.add(tf.keras.layers.Dense(units=50, activation=tf.nn.relu))
model.add(tf.keras.layers.Dense(units=10))
model.add(tf.keras.layers.Softmax())
model.summary()
构建好了模型,下面需要通过 tf.keras.Model
的 compile 方法配置训练过程:
model.compile(
optimizer=tf.keras.optimizers.Adam(learning_rate=0.001), # 设置优化器,这里使用 Adam 优化器,设置学习率为 0.001
loss=tf.keras.losses.categorical_crossentropy, # 设置损失函数,这里使用交叉熵损失
metrics=[tf.keras.metrics.categorical_accuracy] # 设置评估指标,用于检查 y_ture 中最大值对应的 index 与 y_pred 中最大值对应的 index 是否相等
)
batch_size = 32 # 设定 batch_size 为 32
epochs = 50 # 迭代 50 个周期
model.fit(X, y, epochs=epochs, batch_size=batch_size)