数据处理
1、本地数据的读取,进行图片路径读取,标签读取,对标签进行平滑处理。
标签类别转换以及标签平滑
label
label=tf.keras.utils.to_categorical(label,num_classes=10)
label=smooth(label)
def smooth(y,smooth_factor=0.1):
assert len(y.shape)==2
y*=1-smooth_factory
y+=smooth_factory/y.shape[1]
要求训练集和验证集的数据集都可以整除batch_size
i = -2
j = -2
while 1:
if (len(train_img_paths) % batch_size == 0):
break
else:
train_img_paths = train_img_paths[:i]
train_labels = train_labels[:i]
i -= 1
while 1:
if (len(validation_img_paths) % batch_size == 0):
break
else:
validation_img_paths = validation_img_paths[:j]
validation_labels = validation_labels[:j]
j -= 1
tf.keras.Sequence类封装,返回序列数据
对于很多任务来说我们需要做更多的有些自定义预处理,如标签平滑,随机擦除等。
随机擦除
def get_random_eraser(p=0.5, s_l=0.02, s_h=0.4, r_1=0.3, r_2=1/0.3, v_l=0, v_h=255, pixel_level=False):
def eraser(input_img):
img_h, img_w, img_c = input_img.shape
p_1 = np.random.rand()
if p_1 > p:
return input_img
while True:
s = np.random.uniform(s_l, s_h) * img_h * img_w
r = np.random.uniform(r_1, r_2)
w = int(np.sqrt(s / r))
h = int(np.sqrt(s * r))
left = np.random.randint(0, img_w)
top = np.random.randint(0, img_h)
if left + w <= img_w and top + h <= img_h:
break
if pixel_level:
c = np.random.uniform(v_l, v_h, (h, w, img_c))
else:
c = np.random.uniform(v_l, v_h)
input_img[top:top + h, left:left + w, :] = c
return input_img
return eraser
改变图像尺寸到300*300,并且做填充使得图像处于中间
@staticmethod
def center_img(img, size=None,fill_value=255):
h, w = img.shape[:2]
if size is None:
size = max(h, w)
shape = (size, size) + img.shape[2:]
background = np.full(shape, fill_value, np.uint8)
center_x = (size - w) // 2
center_y = (size - h) // 2
background[center_y:center_y + h, center_x:center_x + w] = img
return background
完整代码
class datasequence(Sequence):
def __init__(self,img_paths,labels,batch_size,img_size,use_aug):
self.x_y=np.hstack((np.array(img_paths).reshape(len(img_paths),1),np.array(labels)))
self.batch_size=batch_size
self.img_size=img_size#(300,300)
self.use_aug=use_aug
self.alpha=0.2
self.eraser=get_random_eraser(s_h=0.3,pixel_level=True)
def __len__(self):
return math.ceil(len(self.x_y)/self.batch_size)
@staticmethod
def center(img,size=None,fill_value=255):
h,w=img.shape[:2]
if size is None:
size=max(h,w)
shape=(size,size)+img.shape[2:]
background=np.full(shape,fill_value,np.uint8)
ceter_x=(size-w)//2
ceter_y=(size-h)//2
background[ceter_y:ceter_y+h,ceter_x:ceter_x+w]=img
return background
#处理每张图片,大小,数据增强
def preprocess_img(self,img_path):
img=Image.open(img_path)
scale=self.img_size[0]/max(img.size[:2])
img=img.resize((int(img.size[0]*scale),int(img.size[1]*scale)))
img=img.convert('RGB')
img=np.array(img)
#如果是训练集则进行数据增强
if self.use_aug:
#随机擦除
img=self.eraser(img)
#反转
datagen = ImageDataGenerator(
width_shift_range=0.05,
height_shift_range=0.05,
horizontal_flip=True,
vertical_flip=True,
)
img = datagen.random_transform(img)
img = self.center_img(img, self.img_size[0])
return img
def __getitem__(self, idx):
#获取当前批次的特征值和目标值
batch_x = self.x_y[idx * self.batch_size: self.batch_size * (idx + 1), 0]
batch_y = self.x_y[idx * self.batch_size: self.batch_size * (idx + 1), 1:]
batch_x = np.array([self.preprocess_img(img_path) for img_path in batch_x])
batch_y = np.array(batch_y).astype(np.float32)
return batch_x, batch_y
def on_epoch_end(self):
np.random.shuffle(self.x_y)
模型训练
#建立读取数据
train_sequence,validation_sequence=data_from_sequence()
base_model=EfficientNet.EfficientNetB3(include_top=False, input_shape=(paclasses=param.num_classes)
x=base_model.output
x=GlobalAveragePooling2D(name='avg_pool')(x)
predictions = Dense(param.num_classes, activation='softmax')(x)
model = Model(inputs=base_model.input, outputs=predictions)
#回调函数
callback= tf.keras.callbacks.ModelCheckpoint()
model.fit_generator()
模型的导出
tf.save_model.save(model,'path')
model=tf.saved_model.load('path')
y_pred=model(x)
sparse_categorical_accuracy.update_state(y_true=test_label,
y_pred=y_pred)
总结
数据决定模型的上限,因此数据对于模型的处理至关重要。总共学到了三种data和label的处理方式,第三种比较难sequence。