`我们如何使用 SMOTE 来解决 Tensorflow 中对象检测的类不平衡问题,其中模型输出是标签和 bbox?
这是我的代码,但我无法弄清楚应该在哪里以及如何使用 smote 来解决类不平衡问题?`
import imutils
import os
import cv2
import datetime
import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
import tensorflow as tf
from tensorflow.keras.layers import Flatten
from tensorflow.keras.layers import Dense
from tensorflow.keras.layers import Input
from tensorflow.keras.models import Model
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.preprocessing.image import img_to_array
from tensorflow.keras.preprocessing.image import load_img
from tensorflow.keras.models import load_model
from tensorflow.keras.applications import VGG16, resnet50, inception_v3
from tensorflow.keras.layers import Dropout
from tensorflow.keras.utils import to_categorical
from sklearn.preprocessing import LabelBinarizer
import pickle
import pandas as pd
train_df = pd.read_csv('train.csv')
train_df.head()
print("Num GPUs Available: ", len(tf.config.list_physical_devices('GPU')))
# renaming the columns
train_df = train_df.rename(columns={'img_fName': 'ImageID','img_w':'width','img_h':'height','bbx_xtl':'Xmin', 'bbx_ytl':'Ymin', 'bbx_xbr':'Xmax',
'bbx_ybr':'Ymax', 'class_label':'ClassName'})
train_df.head()
for idx, row in enumerate(train_df):
print(row)
data = []
labels1 = []
bboxes = []
imagePaths = []
for index, row in train_df.iterrows():
(filename, width, height, xmin, ymin, xmax, ymax,class_name) = row
#labels.append(class_name)
Xmin = float(xmin)/width
Ymin = float(ymin)/height
Xmax = float(xmax)/width
Ymax = float(ymax)/height
filename = "train_images/"+filename
image = cv2.imread(filename)
(h,w) = image.shape[:2]
image = load_img(filename, target_size=(224,224))
image = img_to_array(image)
data.append(image)
labels1.append(class_name)
bboxes.append((Xmin, Ymin, Xmax, Ymax))
imagePaths.append(filename)
print(len(imagePaths))
# show the output image
img = plt.imshow(image.astype('uint8'))
#cv2.rectangle(image,(Xmin,Ymin),(Xmax,Ymax),(255,0,0),2)
plt.show()
# convert from the range [0, 255] to [0, 1]
data = np.array(data, dtype="float32") / 255.0
# convert to numpy array
labels = np.array(labels1)
bboxes = np.array(bboxes, dtype="float32")
imagePaths = np.array(imagePaths)
# one-hot encoding on the labels
lb = LabelBinarizer()
labels = lb.fit_transform(labels)
if len(lb.classes_) == 2:
print("two classes")
labels = to_categorical(labels)
split = train_test_split(data,
labels,
bboxes,
imagePaths,
test_size=0.20,
random_state=42)
labels.shape
# unpack the data split
(trainImages, testImages) = split[:2]
(trainLabels, testLabels) = split[2:4]
(trainBBoxes, testBBoxes) = split[4:6]
(trainPaths, testPaths) = split[6:]
#vgg = VGG16(weights="imagenet",
# include_top=False,
# input_tensor=Input(shape=(224, 224, 3)))
InceptionV3 = tf.keras.applications.inception_v3.InceptionV3(
include_top=False,
weights='imagenet',
input_tensor=Input(shape=(224, 224, 3)) #input_shape=None,
# pooling=None,
)
# freeze all layers in order not to train them
InceptionV3.trainable = False
# flatten the max-pooling output of
flatten = InceptionV3.output
flatten = Flatten()(flatten)
# construct a fully-connected layer
# header to output the predicted
# bounding box coordinates
bboxHead = Dense(128, activation="relu")(flatten)
bboxHead = Dense(64, activation="relu")(bboxHead)
bboxHead = Dense(32, activation="relu")(bboxHead)
bboxHead = Dense(4, activation="sigmoid", name="bounding_box")(bboxHead)
# construct a second fully-connected
# layer header to predict
# the class label
softmaxHead = Dense(512, activation="relu")(flatten)
softmaxHead = Dropout(0.5)(softmaxHead)
softmaxHead = Dense(512, activation="relu")(softmaxHead)
softmaxHead = Dropout(0.5)(softmaxHead)
softmaxHead = Dense(len(lb.classes_), activation="softmax", name="class_label")(softmaxHead)
species_class_weights = {
0: 3567/38, #aegypti
1:1.0, # albopictus
2: 3544/63,
3: 3544/3544,
4: 3544/492,
5: 3544/321
}
model = Model(
inputs=InceptionV3.input,
outputs=(bboxHead, softmaxHead))
INIT_LR = 1e-4
NUM_EPOCHS = 20
BATCH_SIZE = 15
losses = {
"class_label": "categorical_crossentropy",
"bounding_box": "mean_squared_error",
}
lossWeights = {
"class_label": species_class_weights,
"bounding_box": 1.0
}
#We need to construct a dictionary for our target training outputs.
trainTargets = {
"class_label": trainLabels,
"bounding_box": trainBBoxes
}
#We need to construct a second dictionary, this one for our target testing outputs.
testTargets = {
"class_label": testLabels,
"bounding_box": testBBoxes
}
opt = Adam(INIT_LR)
model.compile(loss=losses,
optimizer=opt,
metrics=["accuracy"],
loss_weights=lossWeights)
print(model.summary())
` Train Neural Network Here we train our network for bounding box regression and class label prediction.`
H = model.fit(
trainImages, trainTargets,
validation_data=(testImages, testTargets),
batch_size=BATCH_SIZE,
epochs=NUM_EPOCHS,
verbose=1)
我无法找到在哪里以及如何添加 smote 来处理类别不平衡
SMOTE
,我们可以在脚本的开头添加以下内容:
import pandas as pd
from imblearn.over_sampling import SMOTE
train_df = pd.read_csv('train.csv')
# renaming the columns
train_df = train_df.rename(columns={'img_fName': 'ImageID',
'img_w': 'width',
'img_h': 'height',
'bbx_xtl':'Xmin',
'bbx_ytl':'Ymin',
'bbx_xbr':'Xmax',
'bbx_ybr':'Ymax',
'class_label':'ClassName'})
# transform the dataset
X = train_df[['ImageID', 'width', 'height', 'Xmin', 'Ymin', 'Xmax', 'Ymax']]
y = train_df['ClassName']
oversample = SMOTE()
X_res, y_res = oversample.fit_resample(X, y)
``