TinyMind人民币面值&冠字号编码识别挑战赛 - 热身赛
发布时间
阅读量:
阅读量
TinyMind人民币面值&冠字号编码识别挑战赛 - 热身赛
1 数据探索、清洗
1.1 标签
- 读取标签csv文件
train_lables_face_value_path = os.path.join(DATASET, TRAIN_LABELS_FACE_VALUE_FILE)
df_rmb_face_value_labels = pd.read_csv(train_lables_face_value_path,
index_col=None, header=0, delimiter=", ")
- 统计
print("*" * 10)
print(df_rmb_face_value_labels.head(10))
print("*" * 10)
print(df_rmb_face_value_labels.columns)
print("*" * 10)
print(df_rmb_face_value_labels.dtypes)
print("*" * 10)
print(df_rmb_face_value_labels.info())
print("*" * 10)
print(df_rmb_face_value_labels["label"].describe())
**********
name label
0 013MNV9B.jpg 100.0
1 016ETNGG.jpg 50.0
2 018SUTBA.jpg 0.1
3 0192G5IC.jpg 5.0
4 01953EH7.jpg 100.0
5 01AUV9WG.jpg 10.0
6 01B68AKT.jpg 1.0
7 01DMQGVG.jpg 0.1
8 01E9AUX7.jpg 0.1
9 01EAXZMY.jpg 0.2
**********
Index(['name', 'label'], dtype='object')
**********
name object
label float64
dtype: object
**********
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 39620 entries, 0 to 39619
Data columns (total 2 columns):
name 39620 non-null object
label 39620 non-null float64
dtypes: float64(1), object(1)
memory usage: 619.1+ KB
None
**********
count 39620.000000
mean 19.405411
std 33.075336
min 0.100000
25% 0.500000
50% 2.000000
75% 10.000000
max 100.000000
Name: label, dtype: float64
- 面值类别
face_values = np.sort(df_rmb_face_value_labels["label"].unique())
print(face_values)
[ 0.1 0.2 0.5 1. 2. 5. 10. 50. 100. ]
- 样本分布
探索数据是否平衡。
distribution_rmb_face_value = dict()
for face_value in face_values:
distribution_rmb_face_value[str(face_value)] = len(
df_rmb_face_value_labels[df_rmb_face_value_labels["label"] == face_value])
distribution_rmb_face_value = pd.Series(distribution_rmb_face_value)
print(distribution_rmb_face_value)
distribution_rmb_face_value.plot(kind="bar")
plt.xticks(rotation=45)
plt.title("distribution of face values")
plt.show()
1 4233
0.2 4373
0.5 4407
1.0 4424
2.0 4411
5.0 4413
10.0 4283
50.0 4408
100.0 4668
dtype: int64

1.2 样本
通过统计样本图像长宽比,探索样本中是否存在异常值。
df_samples = pd.DataFrame(columns=["width", "height", "ratio"])
for sample_path in glob.glob(os.path.join(DATASET, TRAIN_IMGS_DIR, "*.jpg")):
str_sample_name = os.path.split(sample_path)[-1]
# print(sample_path)
# print(str_sample_name)
img = cv2.imread(sample_path)
height, width = img.shape[0 : 2]
df_samples.loc[str_sample_name] = [width, height, width / height]
print(df_samples.sample(10))
width height ratio
BCEMGK97.jpg 1139.0 579.0 1.967185
4WRU1SYD.jpg 1109.0 571.0 1.942207
V8S7YE61.jpg 1168.0 534.0 2.187266
E63QHM07.jpg 750.0 353.0 2.124646
5Z8OQ73V.jpg 1226.0 600.0 2.043333
CELA9UQV.jpg 1304.0 600.0 2.173333
TEX65YQR.jpg 825.0 394.0 2.093909
WYGL2EFU.jpg 1164.0 600.0 1.940000
3KTP4EOL.jpg 1183.0 600.0 1.971667
H3QNT5ZS.jpg 1310.0 600.0 2.183333
fig = plt.figure(figsize=(8, 6))
df_samples.plot(kind="box", ax=fig.add_subplot(111), subplots=True)
plt.show()
- 异常值
箱形图查找异常样本
p = df_samples["ratio"].plot(kind="box", return_type='dict')
plt.show()
outliers = p["fliers"][0].get_ydata()
outliers.sort()
print(outliers)
outlier_samples = df_samples[(df_samples["ratio"] > 3) | (df_samples["ratio"] < 1.75)]
print(outlier_samples.sort_values(by="ratio"))
上述方式能够排查到非货币图像样本及残币图像样本。

1.3 One-Hot编码
label_encoder = LabelEncoder()
labels = label_encoder.fit_transform(df_data["label"])
labels_one_hot = list(to_categorical(labels, num_classes=num_classes))
1.4 切分数据集
X_train, X_val, y_train, y_val = train_test_split(df_data["name"],
labels_one_hot,
test_size=VAL_RATIO,
shuffle=True)
print("training set X: {}".format(X_train.shape))
print("training set y: {}".format(np.shape(y_train)))
print("validation set X: {}".format(X_val.shape))
print("validation set y: {}".format(np.shape(y_val)))
2 ResNet34面值识别
人民币面值识别为多分类问题,激活函数可选用softmax,网络结构采用ResNet34。
2.1 ResNet34
def Conv2d_BN(x, nb_filter, kernel_size, strides=(1,1), padding="same", name=None):
if name is not None:
bn_name = name + "_bn"
conv_name = name + "_conv"
else:
bn_name = None
conv_name = None
x = Conv2D(nb_filter, kernel_size, padding=padding, strides=strides,
activation="linear", name=conv_name)(x)
x = BatchNormalization(axis=3, name=bn_name)(x)
x = Activation(activation="relu")(x)
return x
def Conv_Block(x, nb_filter, kernel_size, strides=(1,1), is_conv_shortcut=False):
shortcut = x
x = Conv2d_BN(x, nb_filter=nb_filter, kernel_size=kernel_size, strides=strides, padding="same")
x = Conv2d_BN(x, nb_filter=nb_filter, kernel_size=kernel_size, padding="same")
if is_conv_shortcut:
shortcut = Conv2d_BN(shortcut, nb_filter=nb_filter, strides=strides, kernel_size=kernel_size)
x = add([x, shortcut])
return x
def get_model_resnet34(input_shape, num_classes):
input_layer = Input(shape=input_shape)
x = ZeroPadding2D((3,3))(input_layer)
x = Conv2d_BN(x, nb_filter=64, kernel_size=(7,7), strides=(2,2), padding="valid")
x = MaxPooling2D(pool_size=(3,3),strides=(2,2),padding="same")(x)
# (input_shape[0 : 2] / 4, 64)
x = Conv_Block(x, nb_filter=64, kernel_size=(3,3))
x = Conv_Block(x, nb_filter=64, kernel_size=(3,3))
x = Conv_Block(x, nb_filter=64, kernel_size=(3,3))
# (input_shape[0 : 2] / 8, 128)
x = Conv_Block(x, nb_filter=128, kernel_size=(3,3), strides=(2,2), is_conv_shortcut=True)
x = Conv_Block(x, nb_filter=128, kernel_size=(3,3))
x = Conv_Block(x, nb_filter=128,kernel_size=(3,3))
x = Conv_Block(x, nb_filter=128,kernel_size=(3,3))
# (input_shape[0 : 2] / 16, 128)
x = Conv_Block(x, nb_filter=256, kernel_size=(3,3), strides=(2,2), is_conv_shortcut=True)
x = Conv_Block(x, nb_filter=256, kernel_size=(3,3))
x = Conv_Block(x, nb_filter=256, kernel_size=(3,3))
x = Conv_Block(x, nb_filter=256, kernel_size=(3,3))
x = Conv_Block(x, nb_filter=256, kernel_size=(3,3))
x = Conv_Block(x, nb_filter=256, kernel_size=(3,3))
# (input_shape[0 : 2] / 32, 128)
x = Conv_Block(x, nb_filter=512, kernel_size=(3,3), strides=(2,2), is_conv_shortcut=True)
x = Conv_Block(x, nb_filter=512, kernel_size=(3,3))
x = Conv_Block(x, nb_filter=512, kernel_size=(3,3))
x = AveragePooling2D(pool_size=(int(input_shape[0] / 64),
int(input_shape[0] / 64)))(x)
x = Flatten()(x)
x = Dense(num_classes, activation="softmax")(x)
model = Model(inputs=input_layer, outputs=x)
adam = Adam(lr=1e-3)
model.compile(optimizer=adam, loss="categorical_crossentropy", metrics=["accuracy"])
return model
2.2 数据增强
- 样本中货币图像存在残缺、偏转、180度翻转,需要数据增强。
image_data_generator = ImageDataGenerator(
# samplewise_center=True, samplewise_std_normalization=True,
brightness_range=[0.2, 1.5],
zoom_range=0.1,
width_shift_range=0.1, height_shift_range=0.1,
horizontal_flip=False, vertical_flip=False)
img = cv2.flip(img, -1)
- 消除亮度影响,直方图均衡
hsv = cv2.cvtColor(img, cv2.COLOR_RGB2HSV)
hsv[:, :, 2] = cv2.equalizeHist(hsv[:, :, 2].astype(np.uint8))
img = cv2.cvtColor(hsv, cv2.COLOR_HSV2RGB)
2.3 训练
- 监控验证准确率、保存最优模型
best_save = ModelCheckpoint(filepath="{}".format(best_model_path),
monitor="val_acc",
verbose=1,
mode="max",
save_best_only=True,
save_weights_only=False,
period=1)
- 验证准确率未能提升,提前结束训练
early_stop = EarlyStopping(monitor="val_acc",
min_delta=0,
patience=10,
verbose=1,
mode="auto")
- 验证准确率未能提升,减小步长
reduce_learning_rate = ReduceLROnPlateau(monitor="val_acc",
factor=0.2,
patience=5,
epsilon=0.001,
cooldown=0,
min_lr=1e-5)
if __name__ == "__main__":
# 数据读取
data_path = os.path.join(DATASET_DIR, TRAIN_LABELS_FILE)
df_data = pd.read_csv(data_path, index_col=None, header=0, delimiter=", ")
num_classes = len(df_data["label"].unique())
label_encoder_path = "./label_encoder.pickle"
# 标签转换
if os.path.exists(label_encoder_path):
with open(label_encoder_path, "rb") as file_pi:
label_encoder = pickle.load(file_pi)
else:
label_encoder = LabelEncoder()
label_encoder.fit(df_data["label"])
with open(label_encoder_path, "wb") as file_pi:
pickle.dump(label_encoder, file_pi)
labels = label_encoder.transform(df_data["label"])
labels_one_hot = list(to_categorical(labels, num_classes=num_classes))
# 切分数据集
X_train, X_val, y_train, y_val = train_test_split(df_data["name"],
labels_one_hot,
test_size=VAL_RATIO,
shuffle=True)
train_dataset_size = len(y_train)
val_dataset_size = len(y_val)
steps_per_epoch = np.ceil(train_dataset_size / BATCH_SIZE_TRAIN).astype(np.int)
validation_steps = np.ceil(val_dataset_size / BATCH_SIZE_VAL).astype(np.int)
# 数据增强器
image_data_generator = get_image_generator()
best_model_path = os.path.join(MODEL_DIR, "{}_best_model.h5".format(MODEL_NAME))
model_path = os.path.join(MODEL_DIR, "{}_model.h5".format(MODEL_NAME))
history_path = os.path.join(MODEL_DIR, "{}_train_history_dict.p".format(MODEL_NAME))
logger_path = os.path.join(MODEL_DIR, "{}_train_log.p".format(MODEL_NAME))
K.clear_session()
if os.path.exists(best_model_path):
model = load_model(best_model_path)
elif os.path.exists(model_path):
model = load_model(model_path)
else:
model = get_model(MODEL_NAME)(INPUT_SHAPE, num_classes)
history = train(model, image_data_generator,
X_train, y_train,
X_val, y_val,
batch_size_train=BATCH_SIZE_TRAIN,
batch_size_val=BATCH_SIZE_VAL,
steps_per_epoch=steps_per_epoch,
validation_steps=validation_steps,
best_model_path=best_model_path,
model_path=model_path,
history_path=history_path,
logger_path=logger_path,
# is_augmentation=True)
is_augmentation=False)
# list all data in histroy
print(history.history.keys())
# summarize history for accuracy
fig = plt.figure(figsize=(10, 6))
fig.suptitle("model accuracy")
ax = fig.add_subplot(121)
ax.plot(history.history.get("acc"), label="train")
ax.plot(history.history.get("val_acc"), label="validation")
ax.set_xlabel("epoch")
ax.set_ylabel("accuracy")
ax.legend(loc="lower right")
ax = fig.add_subplot(122)
ax.semilogy(1 - np.array(history.history.get("acc")), label="train")
ax.semilogy(1 - np.array(history.history.get("val_acc")), label="validation")
ax.set_xlabel("epoch")
ax.set_ylabel("1 - accuracy")
ax.legend(loc="upper right")
plt.show()
fig.savefig(os.path.join(MODEL_DIR, "{}_acc.png".format(MODEL_NAME)))

3 预测
- 消除亮度影响,直方图均衡
hsv = cv2.cvtColor(img, cv2.COLOR_RGB2HSV)
hsv[:, :, 2] = cv2.equalizeHist(hsv[:, :, 2].astype(np.uint8))
img = cv2.cvtColor(hsv, cv2.COLOR_HSV2RGB)
- 返回Top1
np.argmax(pred_vector, axis=1)
- 预测
y = model.predict(x)
y = reverse_categorical_top1(y)
y = label_encoder.inverse_transform(y)
- 修正非货币图像标签(修正前模型准确率为99.98%,4张非货币图像预测错误;修正后准确率为100%)
def correct_outliers(outliers, predictions):
pd_predictions = pd.DataFrame(predictions, columns=["name", "label"])
# pd_predictions.set_index("name", inplace=True)
for item in outliers:
pd_predictions.loc[pd_predictions.loc[:, "name"] == item, "label"] = 0.2
predictions = pd_predictions.values.tolist()
return predictions
- 写入csv
def predictions_output_csv(filepath, predictions):
with open(filepath, "w") as fw:
fw.write("name, label\n")
for pred in predictions:
if pred[1] >= 1:
pred[1] = int(pred[1])
fw.write("{0[0]}, {0[1]}\n".format(pred))
return None
全部评论 (0)
还没有任何评论哟~
