【初学AI】全球AI攻防挑战赛—赛道二:AI核身之金融场景凭证篡改检测(Datawhale组队学习)

一、背景介绍

 全球AI攻防挑战赛概述  赛道二:金融场景凭证篡改检测(下面我复制粘贴的)

全球AI攻防挑战赛 

在全球人工智能发展和治理广受关注的大趋势下,由中国图象图形学学会、蚂蚁集团、云安全联盟CSA大中华区主办,广泛联合学界、机构共同组织发起全球AI攻防挑战赛。本次比赛包含攻防两大赛道,分别聚焦大模型自身安全和大模型生成内容的防伪检测,涉及信用成长、凭证审核、商家入驻、智能助理等多个业务场景,覆盖机器学习、图像处理与计算机视觉、数据处理等多个算法领域,旨在聚合行业及学界力量共同守护AI及大模型的安全,共同推动AI安全可信技术的发展。

二、赛题相关背景

大赛背景 

在全球人工智能发展和治理广受关注的大趋势下,由中国图象图形学学会、蚂蚁集团、云安全联盟CSA大中华区主办,广泛联合学界、机构共同组织发起全球AI攻防挑战赛。本次比赛包含攻防两大赛道,分别聚焦大模型自身安全和大模型生成内容的防伪检测,涉及信用成长、凭证审核、商家入驻、智能助理等多个业务场景,覆盖机器学习、图像处理与计算机视觉、数据处理等多个算法领域,旨在聚合行业及学界力量共同守护AI及大模型的安全,共同推动AI安全可信技术的发展。

赛题二:AI核身-金融场景凭证篡改检测

金融领域交互式自证业务中涵盖信用成长、用户开户、商家入驻、职业认证、商户解限等多种应用场景,通常都需要用户提交一定的材料(即凭证)用于证明资产收入信息、身份信息、所有权信息、交易信息、资质信息等,而凭证的真实性一直是困扰金融场景自动化审核的一大难题。随着数字媒体编辑技术的发展,越来越多的AI手段和工具能够轻易对凭证材料进行篡改,大量的黑产团伙也逐渐掌握PS、AIGC等工具制作逼真的凭证样本,并对金融审核带来巨大挑战。为此,开设AI核身-金融凭证篡改检测赛道。将会发布大规模的凭证篡改数据集,参赛队伍在给定的大规模篡改数据集上进行模型研发,同时给出对应的测试集用于评估算法模型的有效性。

任务说明 

金融领域交互式自证业务中涵盖用户开户、商家入驻、职业认证、商户解限等多种应用场景,通常都需要用户提交一定的材料(即凭证)用于证明身份信息、所有权信息、交易信息、资质信息等,而凭证的真实性一直是困扰金融场景自动化审核的一大难题。随着数字媒体编辑技术的发展,越来越多的AI手段和工具能够轻易对凭证材料进行篡改,大量的黑产团伙也逐渐掌握PS、AIGC等工具制作逼真的凭证样本,并对金融审核带来巨大挑战。 为此,开设AI核身-金融凭证篡改检测赛道。将会发布大规模的凭证篡改数据集,参赛队伍在给定的大规模篡改数据集上进行模型研发,同时给出对应的测试集用于评估算法模型的有效性。

比赛任务 

在本任务中,要求参赛者设计算法,找出凭证图像中的被篡改的区域。

三、AI在篡改检测中的应用

说白了,就是一个CV的Yolo算法检测(虽然我不太会)

思路:
步骤一:读取数据集

步骤二:构建YOLO数据集

步骤三:训练模型

步骤四:预测测试集

四、比赛数据与评价

数据集介绍 

特别说明:参赛选手不允许使用额外数据

本次比赛将发布超大规模自研光鉴凭证数据集,该数据集整合了大量开源的图像数据和内部的业务数据。数据的构建方式为在原始图像数据上针对文字区域采用copy move,splicing,removal,局部AIGC等方式进行数字篡改编辑。 模型的泛化性也将是此次比赛重要的衡量指标,因此本次的测试集将比训练集包含更多的凭证类型和篡改编辑手法。

数据集格式如下:

  • 训练集数据总量为100w,提供篡改后的凭证图像及其对应的篡改位置标注,标注文件以csv格式给出,csv文件中包括两列,内容示例如下:
PathPolygon
9/9082eccbddd7077bc8288bdd7773d464.jpg[[[143, 359], [432, 359], [437, 423], [141, 427]]]
  • 测试集分为A榜和B榜,分别包含10w测试数据。测试集中数据格式与训练集中一致,但不包含标注文件。

评价指标 

采用Micro-F1作为评价指标,该分数越高表示排名越靠前。每个选手提交的文件中都包含了id和对应的region,我们的评分规则是基于这两个字段进行计算的。首先,我们会判断选手提交结果中的id是否和标签一致,请避免出现遗漏或者溢出,其次,会将选手的提交结果中每个id的region字段与真实标签进行比对和重叠度计算,再结合阈值统计出选手的TP(True Positive)、TN(True Negative)、FP(False Positive)和FN(False Negative)。

𝑃micro =∑𝑛𝑖=1𝑇𝑃𝑖∑𝑛𝑖=1𝑇𝑃𝑖+∑𝑛𝑖=1𝐹𝑃𝑖,𝑅micro =∑𝑛𝑖=1𝑇𝑃𝑖∑𝑛𝑖=1𝑇𝑃𝑖+∑𝑛𝑖=1𝐹𝑁𝑖Pmicro =∑i=1nTPi∑i=1nTPi+∑i=1nFPi,Rmicro =∑i=1nTPi∑i=1nTPi+∑i=1nFNi

接着,我们会计算出选手的准确率P(Precision)和召回率R(Recall)。准确率是指选手正确预测出正例的比例,召回率是指选手正确预测出所有正例的能力。最后,我们将综合考虑各个类别的表现并打分,打分评价指标使用微平均Micro-F1。计算公式如下:

𝐹1micro =2∗𝑃micro ∗𝑅micro 𝑃micro +𝑅micro 


五、代码实践

步骤一:读取数据集

!apt update > /dev/null; apt install aria2 git-lfs axel -y > /dev/null
!pip install ultralytics==8.2.0 numpy pandas opencv-python Pillow matplotlib > /dev/null
!axel -n 12 -a http://mirror.coggle.club/seg_risky_testing_data.zip; unzip -q seg_risky_testing_data.zip
!axel -n 12 -a  http://mirror.coggle.club/seg_risky_training_data_00.zip; unzip -q seg_risky_training_data_00.zip
import os, shutil
import cv2
import glob
import json
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

training_anno = pd.read_csv('http://mirror.coggle.club/seg_risky_training_anno.csv')

train_jpgs = [x.replace('./', '') for x in glob.glob('./0/*.jpg')]
training_anno = training_anno[training_anno['Path'].isin(train_jpgs)]
training_anno['Polygons'] = training_anno['Polygons'].apply(json.loads)

training_anno.head()
training_anno.shape
np.array(training_anno['Polygons'].iloc[4], dtype=np.int32)
idx = 23
img = cv2.imread(training_anno['Path'].iloc[idx])

plt.figure(figsize=(12, 6))
plt.subplot(121)
plt.imshow(img)
plt.title("Original Image")
plt.axis('off')

plt.subplot(122)
img = cv2.imread(training_anno['Path'].iloc[idx])
polygon_coords = np.array(training_anno['Polygons'].iloc[idx], dtype=np.int32)

for polygon_coord in polygon_coords:
    cv2.polylines(img, np.expand_dims(polygon_coord, 0), isClosed=True, color=(0, 255, 0), thickness=2)
    img= cv2.fillPoly(img, np.expand_dims(polygon_coord, 0), color=(255, 0, 0, 0.5))

plt.imshow(img)
plt.title("Image with Polygons")
plt.axis('off')

步骤二:构建YOLO数据集

training_anno.info()
if os.path.exists('yolo_seg_dataset'):
    shutil.rmtree('yolo_seg_dataset')

os.makedirs('yolo_seg_dataset/train')
os.makedirs('yolo_seg_dataset/valid')
def normalize_polygon(polygon, img_width, img_height):
    return [(x / img_width, y / img_height) for x, y in polygon]

for row in training_anno.iloc[10000:].iterrows():
    shutil.copy(row[1].Path, 'yolo_seg_dataset/train')

    img = cv2.imread(row[1].Path)
    img_height, img_width = img.shape[:2]
    txt_filename = os.path.join('yolo_seg_dataset/train/' + row[1].Path.split('/')[-1][:-4] + '.txt')
    with open(txt_filename, 'w') as up:
        for polygon in row[1].Polygons:
            normalized_polygon = normalize_polygon(polygon, img_width, img_height)
            normalized_coords = ' '.join([f'{coord[0]:.3f} {coord[1]:.3f}' for coord in normalized_polygon])
            up.write(f'0 {normalized_coords}\n')
for row in training_anno.iloc[:10000].iterrows():
    shutil.copy(row[1].Path, 'yolo_seg_dataset/valid')

    img = cv2.imread(row[1].Path)
    img_height, img_width = img.shape[:2]
    txt_filename = os.path.join('yolo_seg_dataset/valid/' + row[1].Path.split('/')[-1][:-4] + '.txt')
    with open(txt_filename, 'w') as up:
        for polygon in row[1].Polygons:
            normalized_polygon = normalize_polygon(polygon, img_width, img_height)
            normalized_coords = ' '.join([f'{coord[0]:.3f} {coord[1]:.3f}' for coord in normalized_polygon])
            up.write(f'0 {normalized_coords}\n')
with open('yolo_seg_dataset/data.yaml', 'w') as up:
    data_root = os.path.abspath('yolo_seg_dataset/')
    up.write(f'''
path: {data_root}
train: train
val: valid

names:
    0: alter
''')
!mkdir -p /root/.config/Ultralytics/
!wget http://mirror.coggle.club/yolo/Arial.ttf -O /root/.config/Ultralytics/Arial.ttf
!wget http://mirror.coggle.club/yolo/yolov8n-v8.2.0.pt -O yolov8n.pt
!wget http://mirror.coggle.club/yolo/yolov8n-seg-v8.2.0.pt -O yolov8n-seg.pt

步骤三:训练模型

from ultralytics import YOLO

model = YOLO("./yolov8n-seg.pt")  
results = model.train(data="./yolo_seg_dataset/data.yaml", epochs=30, imgsz=640)

步骤四:预测测试集

from ultralytics import YOLO
import glob
from tqdm import tqdm

model = YOLO("./runs/segment/train/weights/best.pt")  

test_imgs = glob.glob('./test_set_A_rename/*/*')
Polygon = []
for path in tqdm(test_imgs[:10000]):
    results = model(path, verbose=False)
    result = results[0]
    if result.masks is None:
        Polygon.append([])
    else:
        Polygon.append([mask.astype(int).tolist() for mask in result.masks.xy])
import pandas as pd
submit = pd.DataFrame({
    'Path': [x.split('/')[-1] for x in test_imgs[:10000]],
    'Polygon': Polygon
})
submit = pd.merge(submit, pd.DataFrame({'Path': [x.split('/')[-1] for x in test_imgs[:]]}), on='Path', how='right')
submit = submit.fillna('[]')
submit.to_csv('track2_submit.csv', index=None)


六、参与经验

痛跑30轮,,到头来0.0058

被自己气笑了

还得练

对这个代码的本质还不是很了解

还得学!!

七、总结与展望

进军CV方向   学习YOLO图像识别算法

(一个好玩的梗图)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值