基于TensorFlow和Python的机器学习(笔记2)
池化(Pooling)是卷积神经网络中的一个重要的概念,它实际上是一种形式的降采样。有多种不同形式的非线性池化函数,而其中“最大池化(Max pooling)”是最为常见的。它是将输入的图像划分为若干个矩形区域,对每个子区域输出最大值。直觉上,这种机制能够有效的原因在于,在发现一个特征之后,它的精确位置远不及它和其他特征的相对位置的关系重要。池化层会不断地减小数据的空间大小,因此参数的数量和计算量也会下降,这在一定程度上也控制了过拟合。通常来说,CNN的卷积层之间都会周期性地插入池化层。
池化层通常会分别作用于每个输入的特征并减小其大小。目前最常用形式的池化层是每隔2个元素从图像划分出的区块,然后对每个区块中的4个数取最大值。这将会减少75%的数据量。
除了最大池化之外,池化层也可以使用其他池化函数,例如“平均池化”甚至“L2-范数池化”等。
池化操作(Pooling)是CNN中非常常见的一种操作,Pooling层是模仿人的视觉系统对数据进行降维,池化操作通常也叫做子采样(Subsampling)或降采样(Downsampling),在构建卷积神经网络时,往往会用在卷积层之后,通过池化来降低卷积层输出的特征维度,有效减少网络参数的同时还可以防止过拟合现象。
最大池化MaxPooling
平均池化AvgPooling=Average Pooling
主要功能有以下几点:
- 抑制噪声,降低信息冗余
- 提升模型的尺度不变性、旋转不变形
- 降低模型计算量
- 防止过拟合
下图为最大池化过程的示意图:
convolution英 [ˌkɒnvəˈluːʃn] 美 [ˌkɑːnvəˈluːʃn]
- [数] 卷积;回旋;盘旋;卷绕
手写数字识别项目(实战)
# 导入依赖包 import numpy as np import tensorflow as tf import pandas as pd from keras.utils import np_utils from keras.datasets import mnist import matplotlib.pyplot as plt from keras.layers import Dropout # 防止过拟合的层
np.random.seed(10) # 下载数据 (train_image, train_label), (test_image, test_label) = mnist.load_data() # 查看数据信息 print(type(train_image)) print(type(train_label)) # <class 'numpy.ndarray'> # <class 'numpy.ndarray'> print('train_image.shape=', train_image.shape) print('train_label.shape=', train_label.shape) print('test_image.shape=', test_image.shape) print('test_label.shape=', test_label.shape)
# train_image.shape= (60000, 28, 28) # train_label.shape= (60000,) # test_image.shape= (10000, 28, 28) # test_label.shape= (10000,)
# 显示单个图片及其标签 def plot_image(image, label): fig = plt.gcf() fig.set_size_inches(3, 3) fig.suptitle(f'label={label}', color='red') plt.imshow(image, cmap='binary') plt.show()
# 显示单个图片及其标签 # print(train_image[0]) # plot_image(train_image[0],train_label[0])
# 显示系列图片及其标签,和预测值(如有) def plot_images(images, labels, predics, idx, num=10): fig = plt.gcf() # 构造一个图表 fig.set_size_inches(12, 14) # 设置图表尺寸,英寸为单位 if num > 25: num = 25 # 最多显示25张子图 for i in range(num): ax = plt.subplot(5, 5, 1 + i) # 绘制子图,5行5列中的第i+1个 ax.imshow(images[idx], cmap='binary') # 显示图片 以二维矩阵的形式传递图片数据 binary表示灰度显示 title = f'label={labels[idx]}' # 设置子标题 color = 'blue' # 标题颜色 默认blue if predics is not None: # 如有预测信息,则一并显示 index = np.argmax(predics[idx]) # 最大值索引,即预测值 val = str(round(max(predics[idx]), 5)) # 概率 title += f',predict={index}\nmax={val}' # 标题 if labels[idx] != index: color = 'red' # 预测错误,标题红色 ax.set_title(title, color=color, fontsize=10) # 设置子标题 ax.set_xticks([]) # 设置x轴刻度为空,即不显示x轴刻度 ax.set_yticks([]) idx += 1 # 下一个 plt.show() # 显示整个图表
# 显示系列图片及其标签 # plot_images(train_image,train_label,None,100,num=25)
# 对图片数据集进行预处理 # 三维张量改成二维张量 # 第一维不变,第二维变成原第二维和第三维的乘积 # 数据类型转换为float32 print(train_image.shape) # (60000, 28, 28) x_train = train_image.reshape(train_image.shape[0], train_image.shape[1] * train_image.shape[2]).astype('float32') print(x_train.shape) # (60000, 784) print(test_image.shape) # (10000, 28, 28) x_test = test_image.reshape(test_image.shape[0], test_image.shape[1] * test_image.shape[2]).astype('float32') print(x_test.shape) # (10000, 784) print(x_train[0]) # 图像数据归一化,将数据值转换为0-1之间的小数 x_train_norm = x_train / 255 x_test_norm = x_test / 255 print(x_train_norm[0]) # 标签数据预处理,转换为独热码onehot print(train_label[:5]) # [5 0 4 1 9] y_train_onehot = np_utils.to_categorical(train_label) y_test_onehot = np_utils.to_categorical(test_label) print(y_train_onehot[:5]) # [0. 0. 0. 0. 0. 1. 0. 0. 0. 0.]=5
# ■■■建立多层感知模型■■■ # Sequential是线型堆叠容器,相当于多层蛋糕,一层叠一层 # Dense表示浓密的稠密的层,意为连接很稠密的意思,也就是全连接层 from keras.models import Sequential # 模型容器 多层蛋糕 from keras.layers import Dense # 密集层 全连接层
# 建立线型堆叠/多层蛋糕模型 model = Sequential() # 建立输入层input layer和隐藏层hidden layer # 隐藏层神经元个数256,输入层神经元个数784 # 数据初始化采用正态分布的随机数 # normal distribution正态分布随机数 # 初始化的参数包括权重参数weight和偏差参数bias # 指定激活函数为relu热卤 model.add(Dense(units=1000, input_dim=784, kernel_initializer='normal', activation='relu'))
#增加DropOut层,避免过拟合 model.add(Dropout(0.5))
#增加第二个隐藏层,同时增加DropOut层 model.add(Dense(units=1000, kernel_initializer='normal', activation='relu')) model.add(Dropout(0.5)) # 建立输出层 # 输出层神经元个数10 # 数据初始化此阿勇正态分布随机数normal # 初始化的参数包括权重参数weight和偏差参数bias # 定义激活函数为softmax model.add(Dense(units=10, kernel_initializer='normal', activation='softmax')) # 查看模型的【摘要summary】 print(model.summary())
# 模型训练,指定训练方式,也就是模型装配compile # 损失函数指定为【交叉熵】 # 优化器指定为adam,Adam=Adaptive Moment Estimation,自适应矩估计 # 使用Adam优化器可以使模型更快的收敛,并提高准确率 # metrics设置评估模型的方式是准确率accuracy model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy']) # 开始训练
# x输入数据,图像的特征值feature # y数字图像真实值label # validation_split训练数据与验证数据比例,验证数据占训练集的比例为20% # 训练集共60000项数据,将采用其中的60000*0.2=12000项作为验证数据 # epochs轮回次数/轮数,执行10个训练周期 # batch_size每一个批次训练数据个数 # verbose=2 表示显示训练过程 # verbose 0 = silent静默, 1 = progress bar进度条, 2 = one line per epoch每次轮回显示一行数据. # fit=拟合、匹配,overfitting=过拟合 underfittin=欠拟合 train_history = model.fit(x=x_train_norm, y=y_train_onehot, validation_split=0.2, epochs=10, batch_size=200, verbose=2) # train_history数据类型是keras.callbacks.History object # 包含如下字段:epoch、history、model、params、validation_data # epoch是一个训练次数列表,[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] # history是一个字典,包含了训练的历史数据, # history包括4个键 accuracy,val_accuracy,loss,val_loss # 分别是训练数据准确率,验证数据准确率,训练数据损失值,验证数据损失值 # 每个键对应的值都是一个列表,列表元素个数等于输出层神经元个数10 # 'val_loss' = {list: 10} [0.22753198444843292, ...] # history = {dict: 4} {'loss': [0.43830350041389465, ...]
# model是模型数据,包括相当多的信息,例如正则化项 activity_regularizer = {NoneType} None # 参数params = {dict: 3} {'verbose': 2, 'epochs': 10, 'steps': 240} # validation_data = {NoneType} None
print('训练历史数据\n', train_history)
# 训练结果可视化 def show_train_history(train_history): fig = plt.gcf() # 构造一个图表 fig.set_size_inches(10, 8) # 设置图表尺寸,英寸为单位 fig.suptitle('训练数据可视化', color='red') ax1 = plt.subplot(1, 2, 1) # 1行2列的第一个子图表 # 训练数据-准确度 ax1.plot(train_history.history['accuracy'], c='red') # 验证数据-准确度 ax1.plot(train_history.history['val_accuracy'], c='blue') ax1.set_title('训练历史记录-accuracy') # 设置子图表1的标题 ax1.set_xlabel('Epoch') # x轴标签 ax1.set_ylabel('Train') # y轴标签 # 设置子图表1的图例 ax1.legend(['accuracy', 'val_accuracy'], loc='upper left') ax2 = plt.subplot(1, 2, 2) # 1行2列的第二个子图表 # 训练数据-损失值 ax2.plot(train_history.history['loss'], c='red') # 验证数据-损失值 ax2.plot(train_history.history['val_loss'], c='blue') ax2.set_title('训练历史记录-loss') # 设置子图表2的标题 ax2.set_xlabel('Epoch') # x轴标签 ax2.set_ylabel('Train') # y轴标签 # 设置子图表2的图例 ax2.legend(['loss', 'val_loss'], loc='upper left')
plt.show() # 绘制图表
# 训练数据可视化 # accuracy=train accuracy训练准确率 # val_accuracy=validation accuracy验证准确率 # loss=train loss训练损失值记录 # val_loss=validation loss验证损失值记录 show_train_history(train_history)
# 用测试数据来评估模型准确率 # x_test_norm测试数据的feature,图片特征值 # y_test_onehot测试数据的label,图片的真值标签 # 返回在测试模式下模型的损失值和度量值(本例度量值是准确度accuracy)。
scores = model.evaluate(x_test_norm, y_test_onehot) print('测试得分为') print(scores) # 打印准确率数据 # scores = {list: 2} [0.0704198107123375, 0.9787999987602234] # 256个参数 损失值为0.0704198107123375 准确率accuracy为0.9787999987602234 #隐藏层参数增加为1000个 [0.05959093198180199, 0.9830999970436096] #增加DropOut后,[0.05871669948101044, 0.9815999865531921] # 预测,要用标准化、归一化的数据进行预测,批处理32, verbose=1表示显示进度条 prediction = model.predict(x_test_norm, batch_size=32, verbose=1) # 预测数据可视化 # 下标从0开始,共显示25项数据 plot_images(test_image, test_label, prediction, idx=0, num=25)
# 混淆矩阵confusion matrix 也叫误差矩阵 # 混淆矩阵用来显示哪些数次预测比较准确,哪些数字预测容易出错 import pandas as pd
# 独热码转换为普通码 def onehot_convert(predict): res = [] for p in predict: res.append(np.argmax(p)) return res
pre = onehot_convert(prediction) crosstab = pd.crosstab(test_label, pre, rownames=['label'], colnames=['predict']) print(crosstab)
# 建立dataFrame df = pd.DataFrame({'label': test_label, 'predict': pre}) # 查看真实值为5,而预测值为3的数据 df2 = df[(df.label == 5) & (df.predict == 3)] print(df2) # label predict 340 5 3 index = 340 #可视化错误项的图片,分析原因 #plot_image(test_image[index], test_label[index])
|
数据集
训练数据
模型
预测数据
预测错误项
预测结果可视化
模型
添加DropOut层 避免过拟合
|
Model: "sequential" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= dense (Dense) (None, 1000) 785000
dropout (Dropout) (None, 1000) 0
dense_1 (Dense) (None, 10) 10010
================================================================= Total params: 795,010 Trainable params: 795,010 Non-trainable params: 0 _________________________________________________________________ |
增加隐藏层 |
Model: "sequential" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= dense (Dense) (None, 1000) 785000
dropout (Dropout) (None, 1000) 0
dense_1 (Dense) (None, 1000) 1001000
dropout_1 (Dropout) (None, 1000) 0
dense_2 (Dense) (None, 10) 10010
================================================================= Total params: 1,796,010 Trainable params: 1,796,010 Non-trainable params: 0 _________________________________________________________________ |
增加参数导致过拟合
256个参数 |
1000个参数-过拟合 |
|
|
[0.0704198107123375, 0.9787999987602234] loss value & metrics values(accuracy) 损失值&度量值(准确率) |
[0.05959093198180199, 0.9830999970436096] loss value & metrics values(accuracy) 损失值&度量值(准确率) |
优化模型的训练效果对比
参数 |
训练数据可视化 |
结果 |
256个参数 |
|
[0.0704198107123375, 0.9787999987602234] loss value & metrics values(accuracy) 损失值&度量值(准确率)
label predict 340 5 3 1003 5 3 1393 5 3 1670 5 3 2035 5 3 2810 5 3 5937 5 3 5972 5 3 8502 5 3 错误项9个
|
1000个参数 |
|
[0.05959093198180199, 0.9830999970436096] loss value & metrics values(accuracy) 损失值&度量值(准确率)
label predict 340 5 3 1393 5 3 2035 5 3 2597 5 3 2810 5 3 3117 5 3 3902 5 3 4360 5 3 5937 5 3 错误项9个 |
增加DropOut |
|
[0.05871669948101044, 0.9815999865531921]
label predict 340 5 3 1393 5 3 2035 5 3 5937 5 3 错误项4个
|
1000参数+2个隐藏层+DropOut |
|
[0.06338179856538773, 0.9807000160217285]
label predict 1393 5 3 2291 5 3 2597 5 3 5972 5 3 错误项4个
|
结论:使用多层感知器模型识别MNIST手写数字,尝试将模型加宽(增加神经元个数)、加深(增加隐藏层个数),以提高准确率,并加入DropOut层,以避免过度拟合,准确率接近98%。不过,多层感知器有其极限,如果还要进一步提升准确率,就必须使用卷积神经网络CNN。
油耗预测项目(实战)
import io import os.path import matplotlib.pyplot as plt import keras.utils import tensorflow as tf import pandas as pd #下载汽车油耗数据集--加州大学欧文分校 dataset_path = 'C:\\Users\\Administrator\\.keras\\datasets\\auto-mpg.data' if not os.path.exists(dataset_path): dataset_path = keras.utils.get_file('auto-mpg.data', 'http://archive.ics.uci.edu/ml/machine-learning-databases/auto-mpg/auto-mpg.data') # 'C:\\Users\\Administrator\\.keras\\datasets\\auto-mpg.data'
# 利用 pandas 读取数据集,字段有效能(公里数每加仑),气缸数,排量,马力,重量,加速度,型号年份,产地 column_names = ['MPG', 'Cylinders', 'Displacement', 'Horsepower', 'Weight', 'Acceleration', 'Model Year', 'Origin'] #读取数据 raw_dataset = pd.read_csv(dataset_path, names=column_names, na_values='?', comment='\t', sep=' ', skipinitialspace=True) #复制数据 dataset = raw_dataset.copy() #查看数据 print(dataset.head()) print('空白数据个数=', dataset.isna().sum()) #去除空白数据 dataset = dataset.dropna() #查看数据 print('空白数据个数=', dataset.isna().sum()) #产地数据转换为3列,相当于onehot表示形式 # 对于产地地段, 1 表示美国, 2 表示欧洲, 3 表示日本。 origin = dataset.pop('Origin') dataset['USA'] = (origin == 1) * 1.0 dataset['Europe'] = (origin == 2) * 1.0 dataset['Japan'] = (origin == 3) * 1.0 print('tail=\n', dataset.tail()) #划分数据集,其中80%用于训练 20%用于测试 train_dataset = dataset.sample(frac=0.8, random_state=0) test_dataset = dataset.drop(train_dataset.index) #弹出MPG列数据 train_label = train_dataset.pop('MPG') test_label = test_dataset.pop('MPG') #训练数据状态信息 train_stat = train_dataset.describe() # train_stat.pop('MPG') print('train_stat=\n', train_stat) #转置矩阵 train_stat = train_stat.transpose()
#定义数据标准化函数 def norm(x): return (x - train_stat['mean']) / train_stat['std']
#训练数据标准化 normed_train_data = norm(train_dataset) #测试数据标准化 normed_test_data = norm(test_dataset)
print(normed_train_data.shape, train_label.shape) print(normed_test_data.shape, test_label.shape)
train_db = tf.data.Dataset.from_tensor_slices((normed_train_data.values, train_label.values)) train_db = train_db.shuffle(100).batch(32)
import matplotlib
print(matplotlib.matplotlib_fname())
# # 解决plt中文乱码问题-方法1 # # plt.rcParams["font.sans-serif"]=["SimHei"] #设置字体 # # plt.rcParams["axes.unicode_minus"]=False #该语句解决图像中的“-”负号的乱码问题 # # # #创建一个有4个子图表的图表,2行2列 # # 接收数据格式要写成2*2的矩阵形式 # #2 2表示图表行数和列数 # #figsize表示图表尺寸 # #fig用于接收整个图表 # #ax1用于接收第1行第1列的子图表 # #ax2用于接收第1行第2列的子图表 # #ax3用于接收第2行第1列的子图表 # #ax4用于接收第2行第2列的子图表 # fig, [[ax1, ax2], [ax3, ax4]] = plt.subplots(2, 2, figsize=(8, 8)) # #设置图标的居中标题,字号fontsize为20,颜色c为红色 # fig.suptitle('油耗关系曲线',fontsize=20,c='red') # #绘制第1个子图表 # #scatter表示绘制散点图 # #X数据为dataset中的名称为Cylinders的列数据 # #Y数据为dataset中名称为MPG的列数据 # #c表示散点的颜色为red # #edgecolors表示散点的边缘颜色 # #s表示散点的大小size # #linewidth表示边缘的线宽 # ax1.scatter(dataset['Cylinders'], dataset['MPG'], c='red', edgecolors='blue', s=100, linewidth=2) # #设置子图表1的标题 # ax1.set_title('MPG和气缸数 散点图') # #设置子图表1的x轴标签/名称 # ax1.set_xlabel('气缸数') # #设置子图表1的y轴标签/名称 # ax1.set_ylabel('MPG') # #绘制第2个子图表 # ax2.scatter(dataset['Displacement'], dataset['MPG'], c='y', edgecolors='k', s=50, linewidth=2) # ax2.set_title('MPG和排量 散点图') # ax2.set_xlabel('排量') # ax2.set_ylabel('MPG') # #绘制第3个子图表 # ax3.scatter(dataset['Horsepower'], dataset['MPG'], c='g', edgecolors='b', s=40, linewidth=2) # ax3.set_title('MPG和马力 散点图') # ax3.set_xlabel('马力') # ax3.set_ylabel('MPG') # #绘制第4个子图表 # ax4.scatter(dataset['Weight'], dataset['MPG'], c='r', edgecolors='k', s=30, linewidth=2) # ax4.set_title('MPG和重量 散点图') # ax4.set_xlabel('重量') # ax4.set_ylabel('MPG') # #显示图表 # plt.show()
from keras import layers from keras import losses
# 创建模型,3层的全连接网络 class Network(keras.Model): def __init__(self): super(Network, self).__init__() # 创建3个全连接层 self.fc1 = keras.layers.Dense(64, activation='relu') self.fc2 = keras.layers.Dense(64, activation='relu') self.fc3 = keras.layers.Dense(1) def call(self, inputs, training=None, mask=None): # 依次通过 3 个全连接层 x=self.fc1(inputs) x=self.fc2(x) x=self.fc3(x)
return x #创建网络实例 model=Network() model.build(input_shape=(4,9)) #查看网络概述信息 model.summary() #创建优化器,指定超参数 学习率learning rate=0.001 optimizer=tf.keras.optimizers.RMSprop(0.0001)
for epoch in range(2000): for step,(x,y) in enumerate(train_db): with tf.GradientTape() as tape: out=model(x)# 通过网络获得输出 #计算损失函数 loss=tf.reduce_mean(losses.MSE(y,out)) mae_loss=tf.reduce_mean(losses.MAE(y,out)) if step%10==0: print(epoch,step,loss)
# 计算梯度,并更新 grad=tape.gradient(loss,model.trainable_variables) optimizer.apply_gradients(zip(grad,model.trainable_variables))
|