从零入门AI篡改图片检测(金融场景)#Datawhale十月组队学习

1.大赛背景

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

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

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

3.赛题与数据

数据集格式如下:

  • 训练集数据总量为100w,提供篡改后的凭证图像及其对应的篡改位置标注,标注文件以csv格式给出,csv文件中包括两列
  • 测试集分为A榜和B榜,分别包含10w测试数据。测试集中数据格式与训练集中一致,但不包含标注文件。

采用Micro-F1作为评价指标,该分数越高表示排名越靠前。

4.baseline

本任务可以基于检测模型微调,也允许使用基于大模型的方案等。方案不限于:

小模型微调(例如Faster R-CNN、ConvNeXt(Base)+UPerHead、SegNeXt、VAN(B5)+UPerHead等);
使用大模型(例如SAM、Grounded-SAM等);
多模型协同等。

赛事官方给出的baseline是基于SwinTransformer (Large) + Cascade R-CNN的实验结果。

Datawhale提供的是基于yolov8模型的实验结果。

本任务基于Datawhale提供的是基于yolov8模型的baseline展开。

首先需要下载数据集,数据集很大,训练集包括16个文件夹,接近50G.

考虑到机器的限制和训练的效率,使用全量数据来跑是不现实的,也是很贵的。全量数据共有100W+。

那么可行的策略

策略一:就是使用1个train_data来跑,比如training_data-00,跑到收敛,然后再用训好的模型去微调其他数据集。可能需要固定一些层的参数,然后比赛截止前再用全量数据微调一下。提交最后的结果;

策略二:自己采样制作数据集,从16个文件夹中,按一定比例采样数据,最终得到约6W的训练数据集,进行训练,直到收敛。然后再全量数据微调。

在数据处理环节,我们可以查看训练集的样本,可以看到样本的类型,这个样本还是很丰富的。

我用的机器是阿里云V100,单卡,训练6W数据的话,50个epoch需要9h。

感觉这种比赛越来越卷,数据越来越大,对机器的要求越来越高,那么这里面应该是有很多算法工程化的小技巧的,应该是有很多优化的tricks的,这些需要通过不断的实践来提高、积累。

接下里记录一些跑baseline中遇到的问题和解决方法。

1.training_anno = pd.read_csv('./seg_risky_training_anno.csv')

这行代码,baseline里面给的是原始URL,运行有一定概率出现Connection的问题,那么我们可以修改为

!axel -n 12 -a http://mirror.coggle.club/seg_risky_training_anno.csv
training_anno = pd.read_csv('./seg_risky_training_anno.csv')

2.训练集和验证集的划分

baseline里面默认使用了前10000行作为训练集,10000-10150作为验证集,datatrain_00的6W数据没有数据。我们需要采用随机采样来划分训练集和验证集,验证集的比例为0.1。

代码修改后如下:

#随机采样划分训练集和验证集,验证集占比0.1
import os
import shutil
import cv2
import glob
import json
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split

# 定义一个函数,用于归一化多边形的坐标
def normalize_polygon(polygon, img_width, img_height):
    return [(x / img_width, y / img_height) for x, y in polygon]

# 随机划分训练集和验证集,验证集比例为0.1
train_df, valid_df = train_test_split(training_anno, test_size=0.1, random_state=42)

# 处理训练集
for row in train_df.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 valid_df.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')

3.推理

我们每练一次就会产生一个train文件,推理的时候需要使用最新训练好的模型参数,防止弄错模型导致结果错误。

from ultralytics import YOLO
import glob
from tqdm import tqdm

model = YOLO("./runs/segment/train5/weights/best.pt") #注意更新模型,查看segment/train文件夹,防止弄错模型

test_imgs = glob.glob('./test_set_A_rename/*/*')

4.结果提交

原始baseline还存在一个问题,提交的格式不正确,赛事要求的提交格式是

 baseline初版给出的是,yolo_seg输出是一堆坐标点,需要转换为满足[左上,右上,右下,左下]格式的矩形框。

代码修改后如下:

# 初始化一个空列表,用于存储每个图像的多边形掩码
Polygon = []

# 使用 tqdm 包装循环,显示进度条
for path in tqdm(test_imgs[:]):  # 只处理前10000个图像
    # 使用模型对当前图像进行推理
    results = model(path, verbose=False)  # verbose=False 表示不打印推理过程中的详细信息
    
    # 获取第一个结果(假设模型返回的是一个结果列表)
    result = results[0]
    
    # 检查是否有检测到的掩码
    if result.masks is None:
        # 如果没有检测到掩码,添加一个空列表
        Polygon.append([])
    else:
        # 如果检测到了掩码,将每个掩码转换为所需的格式
        processed_masks = []
        for mask in result.masks.xy:
            # 将每个坐标点转换为浮点数
            float_mask = [point.astype(float).tolist() for point in mask]
            
            # 计算边界框的最小和最大坐标
            x_coords = [point[0] for point in float_mask]
            y_coords = [point[1] for point in float_mask]
            min_x, max_x = min(x_coords), max(x_coords)
            min_y, max_y = min(y_coords), max(y_coords)
            
            # 构建左上、右上、右下、左下的坐标点
            polygon = [
                [round(min_x, 1), round(min_y, 1)],  # 左上
                [round(max_x, 1), round(min_y, 1)],  # 右上
                [round(max_x, 1), round(max_y, 1)],  # 右下
                [round(min_x, 1), round(max_y, 1)]   # 左下
            ]
            
            processed_masks.append(polygon)
        
        # 将处理后的多边形添加到 Polygon 列表中
        Polygon.append(processed_masks)

# 此时,Polygon 列表中存储了每个图像的多边形掩码,每个多边形由4个顶点组成

这里面其实还是存在一些问题的,我查看训练集标签发现的。训练集标签中还存在一些:

1)不规则四边形(非矩形,那么按照代码计算最大最小坐标在生成框应该是不准确的,比如可能存在右下坐标(不是max_x,max_y)比这个最大值小一些,那么按照最大值得到就把这个区域扩大了,其他几个顶点类似),我们无法看到测试集的标签分布,所以无法得知测试集是否存在同样情况;

2)我发现训练集标签还存在一些不是4个点的情况,比如6个点,两个大小矩形连在一起,这种情况在模型中是没有考虑的。

这些可能会影响到最终的得分,不过这是TOP选手需要考虑的哈。

上分情况记录:

YOLOV8

模型参数

YOLO11

模型参数

 由于我们需要在有限的资源下,去尽可能取得高分,对比YOLOv8和YOLO11的模型预训练参数,综合考虑下来选择YOLO11s或者YOLO11l可能效果会更好。

目前自己跑下来的情况,YOLOv8n,跑data0文件6W数据,因为没有连续跑,一共跑了10+50+50+90轮,得分情况如下:从60轮到200轮,提分2分。

训练仍未收敛,预计还需要继续跑,不过感觉后面提分情况有限了。

后面准备跑一下YOLO11s看看效果。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/894739.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

pc轨迹回放制作

亲爱的小伙伴,在您浏览之前,烦请关注一下,在此深表感谢! 课程主题:pc轨迹回放制作 主要内容:制作车辆轨迹操作页,包括查询条件、动态轨迹回放、车辆轨迹详情表单等 应用场景:车辆…

sqli-labs less-25a

Sqli-labs less-25a 判断注入类型,列数及注入点 构造 http://192.168.140.130/sq/Less-25a/?id1 回显正常 http://192.168.140.130/sq/Less-25a/?id1’ 报错 构造 http://192.168.140.130/sq/Less-25a/?id1 and 11 回显正常 http://192.168.140.130/sq/Less-25a…

RabbitMQ 入门(三)SpringAMQP五种消息类型(Basic Queue)

一、Spring AMQP 简介 SpringAMQP是基于RabbitMQ封装的一套模板,并且还利用SpringBoot对其实现了自动装配,使用起来非常方便。 SpringAmqp的官方地址:https://spring.io/projects/spring-amqp SpringAMQP提供了三个功能: - 自动…

唐布拉不是家,而我途径它(一)

唐布拉不是家,而我途径它 旅途是一本书,风吹哪页读哪页,笔搁哪句写哪句。 最后一站在唐布拉的尼勒克,晚上11点才到,车停在门口,打开车门就看到这句话: 希望你快乐 今天 明天 天天刚下完雨&am…

2024年诺贝尔物理学奖揭晓:AI背后的“造梦者”是谁?

想象一下,你早上醒来,智能音箱为你播放天气和新闻,中午你用手机刷视频,精准的推荐内容简直和你心有灵犀,晚上回家,自动驾驶汽车安全地把你送回家。这一切看似理所当然,背后却有一双无形的手推动…

双向链表常见接口实现

一 . 链表的分类 链表的结构非常多样,以下情况组合起来就有8种( 2 * 2 * 2 ) 链表结构 : 1.1 单向/双向 1 . 单向 : 只能往一个方向遍历 (仅有一个指针 --> 指向下一个结点的地址), 如下图 : 只能从d1找到d2 , d2 找不到d1 2 . 双向 : 能从两个方向遍历 ( 有指向下一个结点…

Leetcode 841. 钥匙和房间

1.题目基本信息 1.1.题目描述 有 n 个房间,房间按从 0 到 n – 1 编号。最初,除 0 号房间外的其余所有房间都被锁住。你的目标是进入所有的房间。然而,你不能在没有获得钥匙的时候进入锁住的房间。 当你进入一个房间,你可能会在…

深度解析服务级别协议(SLA):保障业务稳定性的关键承诺

前言: 在当今数字化时代,企业的业务连续性和稳定性至关重要。服务级别协议(SLA)作为服务提供商与客户之间的正式承诺,是确保服务质量、可用性、责任的重要工具。SLA不仅定义了服务提供商应达到的服务指标,还…

华为ENSP Truck命令指南:从入门到精通的全方位解析 引言

博客标题:华为ENSP Truck命令指南:从入门到精通的全方位解析 引言 在网络工程的世界里,华为ENSP(Enterprise Network Simulation Platform)作为一款强大的网络模拟工具,为我们提供了在虚拟环境中实践和学习…

MySQL程序介绍<一>

目录 MySQL程序简介 mysqld - MySQL 服务器 ​编辑 mysql - MySQL 命令⾏客⼾端 MySQL程序简介 1.MySQL安装完成通常会包含如下程序: Linux系统程序⼀般在 /usr/bin⽬录下,可以通过命令查看 windows系统⽬录: 你的安装路径\MySQL Server…

【Linux-基础IO】软硬链接+动静态库

一、软硬链接 见一见 软连接 硬连接 通过观察我们发现以下几点: 1.ll - i后,软连接形成的文件有指向,并且软连接的Inode编号与对应文件的Inode编号不一样 2.ll - i后,硬连接形成的文件与对应的文件Inode编号一样 3.软连接…

从零开始在Windows系统上搭建一个node.js后端服务项目

目录 一、下载node.js及配置环境 二、搭建node.js项目及安装express框架 三、集成nodemon,实现代码热部署 四、Express 应用程序生成器 一、下载node.js及配置环境 网上很多安装教程,此处就不再赘述了 版本信息 C:\Users\XXX>node -v v20.15.0…

一个纹理分割的例子

纹理是图像分割常用的特征,即使不是纹理分割。Rafael Gonzalez和Richard Woods的《数字图像处理》中这部分内容片面了。 给一个利用简单的统计特征——熵进行纹理分割的例子。这个例子是说明阈值分割不是仅适用于灰度值的情况,也可以用于纹理&#xff…

【into outfile写文件】

简介 select * from user into outfile C:/Users/ichunqiu/Desktop/PhpStudy2018/PHPTutorial/WWW/1.txt;用法的意思就是把user表中查询到的所有字段都导出到1.txt文件中 我们之前还有学到dumpfile,单是它只能导出一条数据 写入shell 测试注入点 usernameadmin&…

SAP SD学习笔记09 - 受注传票中的不完全Log 和 Business Partner(取引先机能)

好久没写SD了,今天继续写。 上一章讲了SD的如下知识 - SD的售前的流程(引合和見積(询价和报价)) - 数据流的概念,主要就是后传票可以参照前传票,以实现数据的流动,减少输入 - Co…

C++之“构造函数”

文章目录 类的默认成员函数构造函数 类的默认成员函数 默认成员函数就是我们没有在main函数里调用,但是编译器会自动生成的成员函数称为默认成员函数。 C由8个默认成员函数,我们暂时了解6个。 默认成员函数:构造函数,析构函数&a…

面试应该问什么?

在求职者面试的过程中,向面试官提问是一个展现自己积极态度、对职位和公司兴趣以及进一步了解工作环境和职业发展机会的重要环节。以下是一些求职者可以在面试中向面试官提问的问题,这些问题旨在帮助你更全面地了解未来的工作环境、团队文化、以及个人职…

adb devices没找到安卓设备的解决办法

要想让设备让adb识别到,要开启设备的开发者模式,并且开启USB调试功能: 然后重新运行:就找到了

java 文件File类概述

前言 在Java中,File类是一个与文件和目录(文件夹)路径名相关的抽象表示形式。它是java.io包中的一个重要类,用于表示和操作文件系统中的文件和目录。 File类的基本概念 表示路径:File类既可以表示文件路径&#xff…

OpenCV高级图形用户界面(8)在指定的窗口中显示一幅图像函数imshow()的使用

操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 在指定的窗口中显示一幅图像。 函数 imshow 在指定的窗口中显示一幅图像。如果窗口是以 cv::WINDOW_AUTOSIZE 标志创建的,图像将以原…