网络包含8个带权重的层;前5层是卷积层,剩下的3层是全连接层。最后一层全连接层的输出是1000维softmax的输入,softmax会产生1000类c标签的分布网络包含8个带权重的层;前5层是卷积层,剩下的3层是全连接层。最后一层全连接层的输出是1000维softmax的输入,softmax会产生1000类标签的分布。
卷积层的参数 = 卷积核的数量 * 卷积核 + 偏置
卷积层 C2,C4,C5中的卷积核只和位于同一GPU的上一层的FeatureMap相连。从上面可以看出,参数大多数集中在全连接层,在卷积层由于权值共享,权值参数较少。
Relu函数为现在使用比较广泛的激活函数,其表达式为 。当输入x<0时,输出为0;当x>0时,输出等于输入值。
Relu函数相对于前边2种激活函数,有以下优点:
relu函数的计算十分简单,前向计算时只需输入值和一个阈值(这里为0)比较,即可得到输出值。在反向传播时,relu函数的导数为 。计算也比前边2个函数的导数简单很多。
由于relu函数的导数为,即反向传播时梯度要么为0,要么不变,所以梯度的衰减很小,即使网路层数很深,前边层的收敛速度也不会很慢。
Relu函数也有很明显的缺点,就是在训练的时候,网络很脆弱,很容易出现很多神经元值为0,从而再也训练不动。一般我们将学习率设置为较小值来避免这种情况的发生。
为了解决上面的问题,后来又提出很多修正过的模型,比如Leaky-ReLU、Parametric ReLU和Randomized ReLU等,其思想一般都是将x<0的区间不置0值,而是设置为1个参数与输入值相乘的形式,如αx,并在训练过程对α进行修正。
通俗讲解激活函数:
激活函数可以引入非线性因素,解决线性模型所不能解决的问题。
为什么引入Relu呢
class Relu():
"""Relu函数,反向传播时,x>0则会将上游的值原封不动的传递给下游(dx = dout)
x<0则会将信号停在这里(dout=0)
先将输入数据转换为True和False的mask数组"""
def __init__(self):
self.mask = None # mask轮廓的含义,mask是由True/Fase组成的numpy数组。
def forward(self, x):
self.mask = (x <= 0) # mask会将x元素小于等于0的地方保存为True,其他地方都保存为False
out = x.copy() # False的地方输出为x
out[self.mask] = 0 # 将True的地方输出为0
return out
def backward(self, dout):
dout[self.mask] = 0 # 前面保存了mask,True的地方反向传播会停在这个地方,故TRUE的地方设置为0,False的地方是将上游的值原封不动的传递给下游
dx = dout
return dx
Softmax 是用于多类分类问题的激活函数,在多类分类问题中,超过两个类标签则需要类成员关系。对于长度为 K 的任意实向量,Softmax 可以将其压缩为长度为 K,值在(0,1)范围内,并且向量中元素的总和为 1 的实向量。
Softmax 与正常的 max 函数不同:max 函数仅输出最大值,但 Softmax 确保较小的值具有较小的概率,并且不会直接丢弃。我们可以认为它是 argmax 函数的概率版本或「soft」版本。
Softmax 函数的分母结合了原始输出值的所有因子,这意味着 Softmax 函数获得的各种概率彼此相关。
Softmax 激活函数的主要缺点是:
Keras:基于Theano和TensorFlow的深度学习库
Keras是一个高层神经网络API,Keras由纯Python编写而成并基Tensorflow、Theano以及CNTK后端。Keras 为支持快速实验而生,能够把你的idea迅速转换为结果,
特点:
函数
keras.layers.core.Dense ( units, activation=None,
use_bias=True,
kernel_initializer='glorot_uniform',
bias_initializer='zeros',
kernel_regularizer=None,
bias_regularizer=None,
activity_regularizer=None,
kernel_constraint=None,
bias_constraint=None )
函数参数
函数
keras.layers.Conv2D(filters, kernel_size,
strides=(1, 1),
padding='valid',
data_format=None,
dilation_rate=(1, 1),
activation=None, use_bias=True,
kernel_initializer='glorot_uniform',
bias_initializer='zeros',
kernel_regularizer=None,
bias_regularizer=None,
activity_regularizer=None,
kernel_constraint=None,
bias_constraint=None)
函数参数
函数
keras.layers.pooling.MaxPooling2D( pool_size=(2, 2), strides=None, padding='valid', data_format=None )
函数参数
Dropout(x)
X可以取0–1之间,代表百分比抛弃数据
Dropout(0.5)随机抛弃百分之五十的数据
函数
inputs = Input((n_ch, patch_height, patch_width))
conv1 = Convolution2D(32, 3, 3, activation='relu', border_mode='same')(inputs)
conv1 = Dropout(0.2)(conv1)
conv1 = Convolution2D(32, 3, 3, activation='relu', border_mode='same')(conv1)
up1 = UpSampling2D(size=(2, 2))(conv1)
#
conv2 = Convolution2D(16, 3, 3, activation='relu', border_mode='same')(up1)
conv2 = Dropout(0.2)(conv2)
conv2 = Convolution2D(16, 3, 3, activation='relu', border_mode='same')(conv2)
pool1 = MaxPooling2D(pool_size=(2, 2))(conv2)
#
conv3 = Convolution2D(32, 3, 3, activation='relu', border_mode='same')(pool1)
conv3 = Dropout(0.2)(conv3)
conv3 = Convolution2D(32, 3, 3, activation='relu', border_mode='same')(conv3)
pool2 = MaxPooling2D(pool_size=(2, 2))(conv3)
#
conv4 = Convolution2D(64, 3, 3, activation='relu', border_mode='same')(pool2)
conv4 = Dropout(0.2)(conv4)
conv4 = Convolution2D(64, 3, 3, activation='relu', border_mode='same')(conv4)
pool3 = MaxPooling2D(pool_size=(2, 2))(conv4)
#
conv5 = Convolution2D(128, 3, 3, activation='relu', border_mode='same')(pool3)
conv5 = Dropout(0.2)(conv5)
conv5 = Convolution2D(128, 3, 3, activation='relu', border_mode='same')(conv5)
#
up2 = merge([UpSampling2D(size=(2, 2))(conv5), conv4], mode='concat', concat_axis=1)
conv6 = Convolution2D(64, 3, 3, activation='relu', border_mode='same')(up2)
conv6 = Dropout(0.2)(conv6)
conv6 = Convolution2D(64, 3, 3, activation='relu', border_mode='same')(conv6)
#
up3 = merge([UpSampling2D(size=(2, 2))(conv6), conv3], mode='concat', concat_axis=1)
conv7 = Convolution2D(32, 3, 3, activation='relu', border_mode='same')(up3)
conv7 = Dropout(0.2)(conv7)
conv7 = Convolution2D(32, 3, 3, activation='relu', border_mode='same')(conv7)
#
up4 = merge([UpSampling2D(size=(2, 2))(conv7), conv2], mode='concat', concat_axis=1)
conv8 = Convolution2D(16, 3, 3, activation='relu', border_mode='same')(up4)
conv8 = Dropout(0.2)(conv8)
conv8 = Convolution2D(16, 3, 3, activation='relu', border_mode='same')(conv8)
#
pool4 = MaxPooling2D(pool_size=(2, 2))(conv8)
conv9 = Convolution2D(32, 3, 3, activation='relu', border_mode='same')(pool4)
conv9 = Dropout(0.2)(conv9)
conv9 = Convolution2D(32, 3, 3, activation='relu', border_mode='same')(conv9)
#
conv10 = Convolution2D(2, 1, 1, activation='relu', border_mode='same')(conv9)
conv10 = core.Reshape((2,patch_height*patch_width))(conv10)
conv10 = core.Permute((2,1))(conv10)
############
conv10 = core.Activation('softmax')(conv10)
model = Model(input=inputs, output=conv10)
作用
将模型的输入和输出给model函数就会自己组建模型运行图结构
函数
checkpointer = ModelCheckpoint(filepath='./'+name_experiment+'/'+name_experiment +'_best_weights.h5', verbose=1, monitor='val_loss', mode='auto', save_best_only=True)
model.fit(patches_imgs_train, patches_masks_train, epochs=N_epochs, batch_size=batch_size, verbose=1, shuffle=True, validation_split=0.1, callbacks=[checkpointer])
作用
函数
fit(self, x, y, batch_size=32, epochs=10, verbose=1, callbacks=None, validation_split=0.0,
validation_data=None, shuffle=True, class_weight=None, sample_weight=None, initial_epoch=0 )
函数参数
# 加载训练好的模型
model.load_weights('./weights.h5')
predictions = model.predict(patches_imgs_test, batch_size=32, verbose=2)
print("predicted images size :")
print(predictions.shape)
基础配置,环境不做解释
python,Tensorflow,Keras版本匹配
# 基于keras的Alexnet做cifar10数据集分类
import tensorflow as tf
from tensorflow.keras import Model
from tensorflow.keras.layers import Conv2D, BatchNormalization, Activation
from tensorflow.keras.layers import MaxPool2D, Flatten, Dense, Dropout
import os
from matplotlib import pyplot as plt
# 完成数据集的导入
# 使用keras库darasets下载cifar10
cifar10 = tf.keras.datasets.cifar10
# 下载数据训练集,训练集标签,测试集合,测试集标签
(x_train, y_trian), (x_test, y_test) = cifar10.load_data()
# 归一化处理
# 归一化是指归纳同意样本的统计分布性,归一化在0-1之间是统计概率分布
# 归一化处理的目的
# 为了后面数据处理方便,归一化可以避免一些不必要的数值问题。
# 为了程序运行时收敛加快。
# 统一量纲。样本数据的评价标准不一样,需要对其量纲化,统一评价标准。
x_train, x_test = x_train / 255.0, x_test / 255.0
# 定义AlexNet网络结构继承Model
class AlexNet8(Model):
# 构造函数
def __init__(self):
# 父类构造一下
super(AlexNet8, self).__init__()
# 第一次的卷积池化 就完成了
# 第一层卷积层 卷积核96(最后输出通道数) 使用3*3卷积核
self.c1 = Conv2D(filters=96, kernel_size=(3, 3))
# 深度神经网络训练过程中使得每一层神经网络的输入保持相同分布的。
self.b1 = BatchNormalization() # 将每一个batch进行归一化(一个batch是一组,之后权重清空)
# 激活层ReLU(x) = max(0,x)
self.a1 = Activation('relu')
# 池化
# 整个图像中的这种“卷积”会产生大量的信息,这可能会很快成为一个计算噩梦。进入池化层,可将其全部缩小成更通用和可消化的形式。
# 有很多方法可以解决这个问题,最受欢迎的是“最大池”(Max Pooling),它将每个特征图编辑成自己的“读者文摘”版本
# 使用3*3卷积核,卷积步长2
self.p1 = MaxPool2D(pool_size=(3, 3), strides=2)
# 第二次卷积池化 完成
self.c2 = Conv2D(filters=256, kernel_size=(3, 3))
self.b2 = BatchNormalization()
self.a2 = Activation('relu')
self.p2 = MaxPool2D(pool_size=(3, 3), strides=2)
# 第三层
# 第三层没有使用池化层,只有一个卷积层与另外一个激活函数
self.c3 = Conv2D(filters=384, kernel_size=(3, 3), padding='same', activation='relu')
# 第四层 同上
self.c4 = Conv2D(filters=384, kernel_size=(3, 3), padding='same', activation='relu')
# 第五层 同上
self.c5 = Conv2D(filters=256, kernel_size=(3, 3), padding='same', activation='relu')
# 第三次池化
self.p3 = MaxPool2D(pool_size=(3, 3), strides=2)
# 最后一次池化操作后将特征图拉直输入到全连接层
# flatten返回一个一维数组。 将三维拉伸到一维
self.flatten = Flatten()
# 将特征图送入第一层全连接网络 神经元个数(输出个数)2048 激活函数relu
self.f1 = Dense(2048, activation='relu')
# 加入Dropout层 随机丢弃 随机丢弃率0.5
self.d1 = Dropout(0.5)
# 第二个全连接层
self.f2 = Dense(2048, activation='relu')
# 加入Dropout层 随机丢弃 随机丢弃率0.5
self.d2 = Dropout(0.5)
# 将所有元素映射到第三个全连接网络中 神经元10(cifar是10分类) 激活函数softmax 完成10分类
self.f3 = Dense(10, activation='softmax')
def call(self, x):
# 输入经过第一个卷积层
x = self.c1(x)
x = self.b1(x)
x = self.a1(x)
x = self.p1(x)
# 第二个
x = self.c2(x)
x = self.b2(x)
x = self.a2(x)
x = self.p2(x)
# 第三个
x = self.c3(x)
# 第四个
x = self.c4(x)
# 第五个
x = self.c5(x)
# 数据池化
x = self.p3(x)
# 数据拉为一维
x = self.flatten(x)
# 经过各个全连接层
x = self.f1(x)
x = self.d1(x)
x = self.f2(x)
x = self.d2(x)
# 将结果输出
y = self.f3(x)
return y
model = AlexNet8()
model.compile(optimizer='adam',
# 稀疏分类交叉熵损失函数
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=False),
# 系数分类准确率指标
metrics=['sparse_categorical_accuracy'])
# 导入上次训练结果
checkpoint_save_path = "checkpoint/AlexNet8.ckpt"
if os.path.exists(checkpoint_save_path + '.index'):
print(" load the model")
model.load_weights(checkpoint_save_path)
# ModelCheckpoint()函数--保存模型参数
cp_callback = tf.keras.callbacks.ModelCheckpoint(filepath=checkpoint_save_path,
save_weights_only=True, # 是否只保留模型参数
save_best_only=True # 是否只保留最优结果
)
# fit函数 返回的是history对象,history.history 记录损失函数和其他指标的数值变化(epoch)
history = model.fit(x_train, y_trian, batch_size=32, epochs=5, validation_data=(x_test, y_test),
validation_freq=1, # 每一轮之后验证集验证
callbacks=[cp_callback]
)
# model.summary()输出模型各层的参数状况
model.summary()
# # 可视化图
# acc = history.history['sparse_categorical_accuracy']
# val_acc = history.history['val_sparse_categorical_accuracy']
# loss = history.history['loss']
# val_loss = history.history['val_loss']
#
# plt.subplot(1, 2, 1)
# plt.plot(acc, label='Training Accuracy')
# plt.plot(val_acc, label='Validation Accuracy')
# plt.title('Training and Validation Accuracy')
# plt.legend()
#
# plt.subplot(1, 2, 2)
# plt.plot(loss, label='Training Loss')
# plt.plot(val_loss, label='Validation Loss')
# plt.title('Training and Validation Loss')
# plt.legend()
# plt.show()
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wALtI4Rl-1629277241681)(https://z3.ax1x.com/2021/06/04/2Gzy5V.png)]
如图显示:识别正确率>65%
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4DjscpFr-1629277241684)(https://z3.ax1x.com/2021/06/04/2GzLxe.md.png)]
import numpy as np
from tensorflow.keras.preprocessing import image
from tensorflow.keras.layers import Conv2D, BatchNormalization, Activation, MaxPool2D, Dropout, Flatten, Dense
from tensorflow.keras import Model
# 模型存储路径
model_save_path = './checkpoint/AlexNet8.ckpt'
# 加载网络模型
class AlexNet8(Model):
def __init__(self):
super(AlexNet8, self).__init__()
self.c1 = Conv2D(filters=96, kernel_size=(3, 3))
self.b1 = BatchNormalization()
self.a1 = Activation('relu')
self.p1 = MaxPool2D(pool_size=(3, 3), strides=2)
self.c2 = Conv2D(filters=256, kernel_size=(3, 3))
self.b2 = BatchNormalization()
self.a2 = Activation('relu')
self.p2 = MaxPool2D(pool_size=(3, 3), strides=2)
self.c3 = Conv2D(filters=384, kernel_size=(3, 3), padding='same',
activation='relu')
self.c4 = Conv2D(filters=384, kernel_size=(3, 3), padding='same',
activation='relu')
self.c5 = Conv2D(filters=256, kernel_size=(3, 3), padding='same',
activation='relu')
self.p3 = MaxPool2D(pool_size=(3, 3), strides=2)
self.flatten = Flatten()
self.f1 = Dense(2048, activation='relu')
self.d1 = Dropout(0.5)
self.f2 = Dense(2048, activation='relu')
self.d2 = Dropout(0.5)
self.f3 = Dense(10, activation='softmax')
def call(self, x):
x = self.c1(x)
x = self.b1(x)
x = self.a1(x)
x = self.p1(x)
x = self.c2(x)
x = self.b2(x)
x = self.a2(x)
x = self.p2(x)
x = self.c3(x)
x = self.c4(x)
x = self.c5(x)
x = self.p3(x)
x = self.flatten(x)
x = self.f1(x)
x = self.d1(x)
x = self.f2(x)
x = self.d2(x)
y = self.f3(x)
return y
model = AlexNet8()
# 加载已经训练好的网络模型
model.load_weights(model_save_path)
# cafir10数据集 32*32大小 3通道 即:32*32*3 输入特征需要batch*32*32*3
# 将图片加载为指定像素
test_image = image.load_img('img/青蛙.jpg', target_size=(32, 32))
# 转换成array格式 32*32*3
test_image = image.img_to_array(test_image)
# 将3维array格式数据增加一维变成4维 与所需要输入一致
test_image = np.expand_dims(test_image, axis=0)
test_image = test_image / 255.
# 输入图片进行预测
prediction = model.predict(test_image)
# 选出最大概率
pred = max([int(i * 10) for i in prediction[0]]) # 含batchsize的维度
resultDict = {1: '飞机', 2: '汽车', 3: '鸟', 4: '猫', 5: '鹿', 6: '狗', 7: '青蛙', 8: '马', 9: '船', 10: '卡车'}
print("预测图为:", resultDict[pred])
预测图为: 青蛙
上文代码仅仅可以识别32*32分辨率图片,网上下载图片需要更改分辨率。
为了方便导入训练集,以下是把cifar-10转化成jpg的python实现
import numpy as np
import pickle as pkl
import imageio
# 将cifar10数据转化为图片+标签格式
# 定义反序列函数
def unpickle(file):
fo = open(file, 'rb')
dict = pkl.load(fo, encoding='bytes') # 以二进制的方式加载
fo.close()
return dict
# 转换train数据集
for j in range(1, 6):
dataName = "data_batch_" + str(j)
Xtr = unpickle(dataName)
print(dataName + " is loading...")
for i in range(0, 10000):
img = np.reshape(Xtr[b'data'][i], (3, 32, 32))
img = img.transpose(1, 2, 0)
picName = 'train/' + str(Xtr[b'labels'][i]) + '/' + str(
i + (j - 1) */0000) + '.jpg'
imageio.imwrite(picName, img)
print(dataName + " loaded.")
print("test_batch is loading...")
# 转换test数据集
testXtr = unpickle("test/")
for i in range(0, 10000):
img = np.reshape(testXtr[b'data'][i], (3, 32, 32))
img = img.transpose(1, 2, 0)
picName = 'test' + str(testXtr[b'labels'][i]) + '_' + str(i) + '.jpg'
imageio.imwrite(picName, img)
print("test_batch loaded.")
提示: 运行以上python需要手动创建相应folder,以下是批量新建0-9文件夹shell命令
mkdir {1..10}