深度学习(二)
卷积神经网络——CNN
目标识别和分类
实现对图像的高准确率识别
卷积神经网络主要应用于计算机视觉相关任务,不局限于图像,对于序列问题,语音识别也可以应用卷积神经网络。
计算机通过寻找诸如边缘和曲线之类的低级特点来分类图片,继而通过一系列卷积层级建构出更为抽象的概念。这就是CNN工作方式。
CNN 工作的顺序:
一张图片经过
卷积层、非线性层、池化(下采样(downsampling))层、全连接层
最终得到输出。输出可以是描述了图像内容的单独分类或一组分类的概率。
卷积:将卷积核应用到某个张量的所有点上,通过将卷积核在输入的张量上滑动而生成经过滤波处理的张量。
CNN 架构:
卷积层 conv2d
非线性变换层 relu/sigmoid/tanh
池化层 pooling2d
全连接层 w*x + b
作用:突出重要信息,降低噪声
卷积层:
三个参数:ksize 卷积核的大小
strides 卷积核移动的跨度
padding 边缘填充
池化层:
降采样
layers.MaxPooling2D 最大池化
实例
加载数据:pathlib
卫星数据
1、本地数据
data_dir = './data/files' # 本地数据
data_root = pathlib.Path(data_dir)
# 对路径下目录进行迭代
for item in data_root.iterdir():
print(item)
# 提取所有路径
all_image_path = list(data_root.glob('*/*')) # all files
len(all_image_path) # 数据量,列表长度
all_image_path = [str(path) for path in all_image_path] # 将windows路径转换成实际使用的路径
import random
random.shuffle(all_image_path) # 对数据进行乱序
image_count = len(all_image_path) # 记录数据长度
label_names = sorted(item.name for item in data_root.glob('*/')) # 取出目录的名称,要进行分类的类别名
label_to_index = dict((name, index) for index, name in enumerate(label_names)) # 对分类进行编码,用字典的格式保存
# 取出图片的上一级目录,也就是该图片的类别 pathlib.Path('dataset\\pics\\lake\\lake_003.jpg').parent.name all_image_label = [label_to_index[pathlib.Path(p).parent.name] for p in all_image_path] import IPython.display as display index_to_label = dict((v,k) for v,k in label_to_index.items()) # 通过编码找到图片的类别 img_path = all_image_path[0] img_raw = tf.io.read_file(img_path) # 读取图片,得到的是二进制 img_tensor = tf.image.decode_image(img_raw) # 解码图片 # 转换数据类型 img_tensor = tf.cast(img_tensor, tf.float32) # 标准化 img_tensor = img_tensor/255 # 转换成numpy类型 img_tensor.numpy() # tensor array[] 转换成 numpy array[] # 取图片、解码、归一化 def load_preprosess_image(img_path): img_raw = tf.io.read_file(img_path) # 读取图片,得到的是二进制 # img_tensor = tf.image.decode_image(img_raw) # 解码图片,可解码所有类型,缺点是不反悔原有的shape img_tensor = tf.image.decode_jpeg(img_raw,channel=3) # 解码图片,用对应格式的解码方式
img_tensor = tf.image.resize(img_tensor,[256,256]) # 裁剪图片,会变形,对机器识别没有影响,resize_image_with_crop_or_pad()不会变形
img_tensor = tf.cast(img_tensor, tf.float32)
img = img_tensor/255
return img
image_path = all_image_path[100]
plt.imshow(load_preprosess_image(image_path))
构造 tf.data
# 构造 tf.data
path_ds = tf.data.Dataset.from_tensor_slices(all_image_path)
image_dataset = path_ds.map(load_preprosess_image)
# 加载 label
label_dataset = tf.data.Dataset.from_tensor_slices(all_image_label)
# 把image_dataset, label_dataset 合成一个 dataset
dataset = tf.data.Dataset.zip((image_dataset, label_dataset))
test_count = int(image_count*0.2)
train_count = image_count - test_count
# 划分训练数据和测试数据
train_dataset = dataset.skip(test_count)
test_dataset = dataset.take(test_count)
BATCH_SIZE = 32
train_dataset = train_dataset.repeat().shuffle(buffer_size=train_count).batch(BATCH_SIZE) # repeat()源源不断产生数据
test_dataset = test_dataset.batch(BATCH_SIZE)
# 建立模型
model = tf.keras.Sequential()
model.add(tf.keras.layers.Conv2D(64, (3, 3), input_shape=(256, 256, 3), activation='relu'))
model.add(tf.keras.layers.Conv2D(64, (3, 3), activation='relu'))
model.add(tf.keras.layers.MaxPooling2D())
model.add(tf.keras.layers.Conv2D(128, (3, 3), activation='relu'))
model.add(tf.keras.layers.Conv2D(128, (3, 3), activation='relu'))
model.add(tf.keras.layers.MaxPooling2D())
model.add(tf.keras.layers.Conv2D(256, (3, 3), activation='relu'))
model.add(tf.keras.layers.Conv2D(256, (3, 3), activation='relu'))
model.add(tf.keras.layers.MaxPooling2D())
model.add(tf.keras.layers.Conv2D(512, (3, 3), activation='relu'))
model.add(tf.keras.layers.MaxPooling2D())
model.add(tf.keras.layers.Conv2D(512, (3, 3), activation='relu'))
model.add(tf.keras.layers.MaxPooling2D())
model.add(tf.keras.layers.Conv2D(1024, (3, 3), activation='relu'))
model.add(tf.keras.layers.GlobalAveragePooling2D())
model.add(tf.keras.layers.Dense(1024, activation='relu'))
model.add(tf.keras.layers.Dense(256, activation='relu'))
model.add(tf.keras.layers.Dense(1, activation='sigmoid'))
model.compile(optimizer='adam',
loss='categorical_crossentropy',
metrics=['acc'])
steps_per_epoch = train_count//BATCH_SIZE
validation_steps = test_count//BATCH_SIZE
history = model.fit(train_image, epochs=30, steps_per_epoch = steps_per_epoch, validation_steps = validation_steps)
批标准化
标准化:即归一化,将数据映射到指定的范围,用于去除不同维度的数据的量纲以及量纲单位。有助于模型的学习与对新数据的泛化。
标准化和归一化
将数据减去其平均值使其中心为 0,然后将数据除以其标准差使其标准差为 1。
批标准化(Batch Normalization)
优化神经网络的一种方法
不仅在数据输入模型之前对数据做标准化,在网络的每一次变换之后都应该考虑数据标准化。
即使在训练过程中均值和方差随时间发生变化,它也可以适应性地将数据标准化
批标准化解决了梯度消失和梯度爆炸问题。是一种训练优化方法。
批标准化的好处:
数据预处理做标准化可以加速收敛,在神经网络使用标准化也可以加速收敛,并且具有正则化效果,提高模型的泛化能力,允许更高的学习速率从而加速收敛。
批标准化有助于梯度传播,因此允许更深的网络。对于有些特别深的网络,只有包含多个 BatchNormalization 层时才能进行训练。BatchNormalization 广泛应用于 Keras 内置的许多高级卷积神经网络架构,如 ResNet50、InceptionV3、Xception。
BatchNormalization 层通常在卷积层或密集连接层之后使用。
Tf.keras.layers.BatchNormalization()
批标准化实现过程:
1、求每一个训练批次数据的均值
2、求每一个训练批次数据的方差
3、数据进行标准化
4、训练参数 γ,β
5、输出 y 通过 γ,β 线性变换得到原来的数值
在训练的正向传播中,不会改变当前输出,只记录下 γ,β。
在反向传播的时候,根据求得的 γ,β 通过链式求导方式,求出学习速率以至改变权值。
批标准化的预测过程:
对于预测阶段时使用的均值和方差,其实也是来源于训练集。比如我们在模型训练时我们就记录下每个 batch 下的均值和方差,待训练完毕后,我们求整个训练样本的均值和方差期望值,作为我们进行预测时进行 BN 时的均值和方差。
批标准化使用位置:
training:Python 布尔值,指示图层应在训练模式还是推理模式运行
training=True:该图层使用当前批输入的均值和方差对其输入进行标准化
training=False:该图层使用在训练期间学习的移动统计数据的均值和方差来标准化其输入
BN 放在全连接层和激活函数后面效果可能会更好。