ML、DL、CNN学习记录3
# coding: utf-8
# Date:2020/8/15 19:16
# @Author: hcf
# @Name: layer_name_intro
import os
import numpy as np
import pandas as pd
# import keras
import tensorflow.keras as keras
# 序贯模型
from keras.models import Sequential, Model
# 模型的层
from tensorflow.python.keras.layers import Conv2D, MaxPool2D, Flatten, ReLU, Dense
# 数据集合
from keras.datasets import mnist
"""
from . import mnist
from . import imdb
from . import reuters
from . import cifar10
from . import cifar100
from . import boston_housing
from . import fashion_mnist
"""
# 加载已经训练完成的模型
from tensorflow.python.keras.models import load_model
# 梯度下降方法
from tensorflow.python.keras.optimizer_v2.gradient_descent import SGD
# one-hot 编码
from tensorflow.python.keras.utils.np_utils import to_categorical
# 图片读取,写入(op)
import cv2
# 交叉熵
from tensorflow.python.keras.losses import categorical_crossentropy
if __name__ == '__main__':
# 加载的数据在c盘的 .keras文件夹中
# 训练集:60 000
# 测试集:10 000
(x_train,y_train), (x_test,y_test) = mnist.load_data()
# print(x_train)
# print(type(x_train))
# print(x_train.shape)
# ==================================
# 数据预处理
# ==================================
# 每张图的结构 (28,28) ==> (28,28,1)
# 所以需要进行转换
x_train = x_train.reshape((-1, 28, 28, 1))
x_test = x_test.reshape((-1, 28, 28, 1))
# 数据类型的one-hot编码
# 1 2 3 4 ... 10
# 1000000000 010000000 0010000000 0001000000 ... 0000000001
y_train = to_categorical(y_train)
y_test = to_categorical(y_test)
''' 进行数据处理
output_path = 'mnist/'
if not os.path.exists(output_path):
os.makdir(output_path)
m,w,h = x_train.shape
for i in range(m):
img = x_train[i]
c = y_train[i]
if not os.path.exists():
img_path = os.path.join(output_path, str(c))
os.mkdir(img_path)
img_path = os.path.join(output_path, str(c))
cv2.imwrite(img_path + str(i)+'.png',img)
'''
# =================================================
# 模型建立
# =================================================
# 判断模型是否已经存在后
if os.path.exists('model_mnist.h5'):
print('加载模型!!!')
model = load_model('model_mnist.h5')
else:
# 代表序贯模型
model = Sequential()
# Image(28,28,1)
# filter: 过滤器 ==> 生成的下一层通道数目
# 卷积核大小 kernel_size = 5 ==> (5, 5)
# 激活函数activation = relu
# 初始的输入层 才需要设置 input_shape=(28, 28, 1)
model.add(Conv2D(filters=6, kernel_size=5, padding='same', activation='relu', input_shape=(28, 28, 1)))
# padding 是否增加 全零
model.add(MaxPool2D(pool_size=(2, 2), padding='same'))
# 一个二维的卷积层
conv_layer = Conv2D(filters=16, kernel_size=5, padding='same', activation='relu')
# 可以设置 让这一层不进行训练
conv_layer.trainable = False
model.add(conv_layer)
# padding 是否增加 全零
model.add(MaxPool2D(pool_size=(2, 2), padding='same'))
# 拉平(向量化)
model.add(Flatten())
# 全连接
model.add(Dense(64, activation='relu'))
# 主义数据需要 one-hot编码
model.add(Dense(10, activation='softmax'))
print('model structure')
# 打印网络模型信息
model.summary()
# ================================
# 模型训练
# ================================
# 给定损失函数, 损失函数用于判断模型工作好不好的,决定了模型结果的好坏
# 交叉熵 = cross Entropy = -ln(y_pred(yi))
# loss = -sum(y_pred(yi))
# For example :
# 误差损失平方和 loss = sum(yi- yi_pred)**2
# 0 0 1 0 预测结果 交叉熵
# P1 0.1 0.2 0.4 0.3 Yes -ln0.4
# P2 0.01 0.02 0.90 0.07 Yes -ln0.9
# 但是 P2 的效果更好,
# 损失loss:交叉熵
# 优化器SGD:梯度下降
# epoch 一个 epoch 中有若干个 batch
# 梯度下降是每个batch中进行梯度下降
# metrics: 准确率
model.compile(loss=categorical_crossentropy, optimizer=SGD(lr=0.001), metrics=['acc'])
# epochs=10 : 训练多少轮
# batch_size=128: 每轮训练中将 128 个当做一批
# model.fit(x_train, y_train, batch_size=128, epochs=10, validation_split=[x_test,y_test]])
history = model.fit(x_train, y_train, batch_size=128, epochs=10, validation_split=0.1)
# 可以打印结果,
print(history.history)
model.save('model_mnist.h5')
# y_test_pred = model.predict(x_test)
result =model.evaluate(x_test, y_test)
print('测试结果:', result)
# ================================================================================
# 访问模型隐层
# ================================================================================
from keras.applications.vgg16 import VGG16, preprocess_input, decode_predictions
from keras.preprocessing import image
base_model = model
img_path = 'son.png'
output_path = './Layer/'
img = image.load_img(img_path, target_size=(224,224))
x = image.img_to_array(img)
x = np.expand_dims(x, axis=0)
x = preprocess_input(x)
if not os.path.exists(output_path):
os.mkdir(output_path)
# 遍历模型的每一层
for layer in base_model.layers:
# 打印层信息
# <tensorflow.python.keras.layers.convolutional.Conv2D object at 0x000001F2DC259828>
print(layer)
layer_path_name = os.path.join(output_path, layer.name)
# 打印层名
print(layer_path_name)
if not os.path.exists(layer_path_name):
os.mkdir(layer_path_name)
# 将某一隐藏层作为模型的输出
model = Model(inputs=base_model.input, outputs=layer.output)
# 进行图片预测
feature_maps = model.predict(x[:, :, 0])[0]
if len(feature_maps.shape) < 2:
continue
# 获取这一层的通道数目
channel_size = feature_maps.shape[2]
for c in range(channel_size):
# 获取某一通道的图像
feature_map = feature_maps[:, :, c]
# 最大最小值得差 大于0.1时候
if np.ptp(feature_map) > 0.1:
feature_map = 255*(feature_map - np.min(feature_map)) / np.ptp(feature_map) # 将255改成其他值,看相应结果
feature_map_path = os.path.join(output_path, layer.name, str(c+1)+'.jpg')
# 存储 layer 层,第 c 个通道的图像
cv2.imwrite(feature_map_path, feature_map)
print('='*40)
model.summary()
Transfer Learning
使用已经存在的模型处理自己的问题,模型的改造
# include_top=True 考虑最后的全连接
# include_top=False 不考虑后面的全连接
model = ResNet50(weights='imagenet', include_top=False)
Input:
输入必须是模型的设定的大小
output:
需要有自己的输出,所以一般来说不需要之前模型的全连接Dense层。