比赛代码准备
前言
这篇文章是针对这次比赛的思路梳理和代码笔记
这次比赛在代码方面主要分为两部分
- 视觉检测模型的 数据预处理 和 神经网络结构+超参数的调优
- 误差补偿模型的 数据清洗
视觉检测任务的数据清洗
滤波器
根据给到噪声图像的噪声类型选择相应的滤波器
import cv2
image_path = "./image/1ac1e8a095df4611af387d9934799251/train/0"
for file in os.listdir(image_path):
img = cv2.imread(image_path+"/"+file)
img = cv2.medianBlur(img, 5) # 中值滤波器 应用于去除椒盐噪声
img = cv2.GaussianBlur(img,(5,5),0) # 高斯滤波器 应用于去除高斯噪声
img = cv2.blur(img,5) # 均值滤波器 应用于去除均匀噪声
cv2.imwrite(file,img)
视觉检测的数据预处理
该任务的数据预处理集中在图像预处理方面 在比赛方给定的代码中,预处理的一些方法只能写在
process_base64_image() 的函数中:
def process_base64_image(s):
img = tf.io.decode_base64(s)
img = tf.io.decode_png(img, channels=3)
img = tf.image.resize(img, (img_height, img_width), antialias=True)
return img
我们需要的就是在该代码当中加入数据预处理的代码
img = tf.image.flip_left_right(img) # 左右平移
img = tf.image.flip_up_down(img) # 上下平移
img = tf.image.random_brightness(img,max_delta = 1.1) # 随机改变亮度
img = tf.image.random_contrast(img,lower=0.9,upper=1.1) # 随机改变对比度
- tf.image.flip_left_right(img)
该方法指让图片随机左右平移,平移可以帮助模型理解图像在空间中变化的关系
- img = tf.image.flip_up_down(img)
该方法指让图片随机上下平移,平移可以帮助模型理解图像在空间中变化的关系
- img = tf.image.random_brightness(img,max_delta = 1.1)
这个操作可以随机调整图像的亮度,这可以帮助模型更好地理解图像的光照条件
- img = tf.image.random_contrast(img,lower=0.9,upper=1.1)
这个操作可以随机调整图像的对比度。这可以让模型更好地理解图像中的颜色和形状
视觉检测模型的网络结构及超参数
该任务是核心部分
训练出来的模型精准度决定了比赛的生产部分的得分情况
首先是数据部分,经过试验 发现合格 与不合格的图片数量最好 保持相等 ,这样模型的损失曲线更容易向下收敛
其次是网络结构
经过试验 采用le-net网络 模型收敛的情况会更好一些:
# 构建模型
model = tf.keras.Sequential([
layers.Lambda(
(
lambda x: tf.map_fn(
process_base64_image,
x,
fn_output_signature=tf.TensorSpec(shape=(int(img_height), int(img_width), 3), dtype=tf.float32))
),
name='decode_base64_png'
),
layers.Rescaling(1./255,offset=-1), # 归一化处理
tf.keras.layers.Conv2D(6,(5,5), activation='relu', input_shape=(img_height,img_width,3)),
tf.keras.layers.MaxPool2D(2,2),
tf.keras.layers.Conv2D(16,(5,5),activation='relu'),
tf.keras.layers.MaxPool2D(2,2),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(120,activation='relu'),
tf.keras.layers.Dense(84,activation='relu'),
tf.keras.layers.Dense(2,activation='sigmoid')
])
该网络的lambda层下面加了一个归一化层,该操作也可以算作是图像预处理部分
接着是两层的卷积层 这两层都是按照le-net模型的参数设计的
- 第一层卷积6个神经元 使用5x5的卷积核
- 第二层池化使用2x2的矩阵
- 第三层卷积16个神经元 使用5x5的卷积核
- 第四层池化使用2x2的矩阵
- 第五层是个线性层 固定放在卷积层后面
- 第六层全连接 使用120个神经元 激活函数选择relu
- 第七层全连接 使用84个神经元 激活函数选择relu
- 第八层输出层 2个神经元(因为两个类别) 由于是二分类问题 选择sigmoid激活函数
最后是网络的超参数
超参数主要集中在编译模型的地方
编译模型时,我们采用Adam优化器 步长 选择0.001 这样处理少量数据收敛效果会很好
注意: 如果想要指定学习率,必须使用tf.keras.optimizers.Adam(0.001,clipnorm=True)
损失函数的选择上 采用交叉熵 使用tf.losses.SparseCategoricalCrossentropy(from_logits=True)指定
选择这个损失函数是因为经过试验这个效果更好
# 编译模型,选择损失函数、优化器和性能指标
model.compile(optimizer=tf.keras.optimizers.Adam(0.001,clipnorm=1),
loss=tf.losses.SparseCategoricalCrossentropy(from_logits=True),
metrics=['accuracy'])
误差补偿模型的数据清洗
该比赛给的数据都是数字型的数据,所以不考虑其他数据类型的数据清洗
因此对于这样的数据 有三个万金油的处理方法 删除重复行 、 填充空值和删除异常数据
数据格式转换
将所有数据转换成数字类型 确保输入的数据不出现异常
for col in train_dataset.columns:
if train_dataset[col].dtype == 'object':
train_dataset[col] = pd.to_numeric(train_dataset[col],errors='coerce').fillna(0)
删除重复行
可以 提高数据的质量和准确性
data.drop_duplicates(inplace=True) # 删除重复行
填充空值
提高数据的完整度
填充空值可以填充均值也可以填充中位数(推荐中位数 目前数据中可能存在异常数据)
for col in data.columns:
quantile = data[col].quantile()
data[col].fillna(quantile,inplace=True)
删除异常数据
使用iqr方法找出异常数据
IQR方法是一种基于四分位数的异常值检测方法。
它通过计算每个数据点与四分位数之间的距离,来衡量数据点的离散程度。
如果某个数据点距离四分位数的距离超过1.5倍的四分位距,则可以将其视为异常值并剔除。
这样的方法可以 使数据更平滑 便于模型计算
# 去除异常值 使数据更平滑 便于计算
for col in data.columns:
q1 = data[col].quantile(0.25)
q3 = data[col].quantile(0.75)
iqr = q3 - q1
# print(iqr)
data[col] = data[(data[col] > (q1 - 1.5*iqr)) & (data[col] < (q3 + 1.5*iqr))][col]
data.dropna(inplace=True)
-
保存
data.to_csv(“./adjustments.tsv”,index=False,sep=‘\t’)
误差补偿的网络结构以及编译参数
norm_layer = preprocessing.Normalization()
norm_layer.adapt(train_features)
model = tf.keras.Sequential([
norm_layer,
layers.Dense(100, input_dim=train_features.shape[1], activation="elu"),
layers.Dense(32, activation="elu"),
layers.Dense(64, activation="elu"),
layers.Dense(128, activation="elu"),
layers.Dense(train_labels.shape[1])
])
model.compile(loss="mse", optimizer="adam") # 根据情况调整参数
model.summary()
这里使用五层全连接网络 并且在全连接之前还做了一个标准化的操作 该操作应该也算一个预处理方式
- 第一层全连接 100个神经元
- 第二层全连接 32个神经元
- 第三层全连接 64个神经元
- 第四层全连接 128个神经元
- 第五层输出层
注意:误差补偿模型可以一次性多训练几轮 建议100轮
再补一段代码:如果比赛时图片太少了导致训练效果不好可以运行这段代码增加图片数量
import os
from PIL import Image,ImageEnhance
import cv2
image_path = "./image/1ac1e8a095df4611af387d9934799251/"
file_list = ['train/', 'dev/', 'test/']
for path in file_list:
for i in range(2):
tmp_path = image_path + path + str(i)
for file in os.listdir(tmp_path):
img = Image.open(tmp_path + '/' + file)
image_enhance = ImageEnhance.Brightness(image).enhance(1.5)
image_enhance = ImageEnhance.Contrast(image).enhance(1.5)
image_enhance = ImageEnhance.Color(image).enhance(1.5)
image_enhance.save(image_path+file)