qidao123.com技术社区-IT企服评测·应用市场

标题: 【验证码辨认专栏】大炮打麻雀 — CLIP 图文多模态模型,人均通杀 AIGC 六 [打印本页]

作者: 温锦文欧普厨电及净水器总代理    时间: 2024-11-1 08:12
标题: 【验证码辨认专栏】大炮打麻雀 — CLIP 图文多模态模型,人均通杀 AIGC 六

前言

近期有粉丝私信,不知道如何训练某讯系点选验证码,之前星球群也有不少粉丝讨论相干问题,为满足粉丝们的需求,本文将对这型验证码的训练进行讲解, 文末可以下载相干的工具,包罗 文章配套标注工具 + 文章配套训练代码 + 部门学习数据集(少量类目,仅供学习使用,不设计成品) + 六宫格推理比较算法 。已参加星球 > 3 天的成员可以免费下载:


CLIP 简介

CLIP(Contrastive Language-Image Pre-Training)是由 OpenAI 在 2021 年发布的一种多模态预训练神经网络模型,旨在将图像和自然语言的表现空间统一起来,使得它们可以相互理解和关联。CLIP 的出现标志着计算机视觉领域的一次重大突破,它展示了使用自然语言监督来训练图像模型的强大本事。与以往的图像分类模型不同,CLIP 并没有使用大规模的标注图像数据集来进行训练,而是通过自监督对比学习的方式从未标注的图像进行预训练,以便使得模型更好的理解图像和文本之间的关系,这种模型我们称为双塔模型。整体流程如下:

每张图像都有一句表明性文字。将文字和图片分别通过一个编码器得到向量,文本编码器常用的是 Bert,而图片编码器则是 resnet 或者 vit,更多详细内容可以检察 OpenAI 相干资料:https://github.com/OpenAI/CLIP?tab=readme-ov-file。
1. 模型架构

CLIP 的焦点思想是使用对比学习(contrastive learning),通过对图像和文本进行共同训练,来学习两者之间的关联。CLIP 模型由两部门组成:

在训练过程中,CLIP 将大量图像-文本对作为输入,使用对比学习的方法,使相对应的图像和文本特征向量尽大概接近,而不匹配的图像和文本对的特征向量则尽大概阔别。
2. 预训练数据和任务

CLIP 的训练使用了来自互联网的大规模图像-文本对(凌驾 4 亿对)。这些数据包罗了非常多样化的内容,涵盖了自然语言和视觉场景的各种情势和细节。
CLIP 不依赖于传统的任务特定标签(如 ImageNet 数据集中的种别标签),而是通过从互联网上自然收集的图像和文本对进行训练。CLIP 模型通过学习图像和文本的对齐关系,可以理解图像中物体的复杂概念及其相干的文本形貌。
3. 多任务本事

CLIP 在预训练过程中,学习了广泛的任务,包罗:

4. 优势

CLIP 在多个任务上展示出了超越传统监督学习模型的本事,尤其是在以下几个方面:

5. 应用场景

CLIP 的通用性使其在很多实际应用中显现了巨大潜力,包罗但不限于:

Chinese-CLIP

在上文相识了 CLIP 之后,我们对图文相似度有了一定认知,CN-CLIP 则是 CLIP 的汉化,使用了全新的训练方式,最原始的 CLIP 仅支持英文,倘若我们每次必要将中文翻译成英文去做检索和相似度计算,这种不光存在精度问题,而且还存在弊端,所以便有了 Chinese-CLIP 模型。 拥有处理多模态数据的本事。初始阶段以预训练的方式设定了两种编码器:一种是 CLIP 的视觉编码器,另一种是中文版本的 RoBERTa 文本编码器,更多详细先容见 Git: https://github.com/OFA-Sys/Chinese-CLIP。
CNCLIP 使用的数据集为 ~2 亿图文对, Chinese-CLIP 目前开源 5 个不同规模如下:
模型规模

模型规模视觉侧骨架参数量文本侧骨架文本侧参数量分辨率CN-CLIPRN50ResNet5077MRBT339M224CN-CLIPViT-B/16ViT-B/16188MRoBERTa-wwm-Base102M224CN-CLIPViT-L/14ViT-L/14406MRoBERTa-wwm-Base102M224CN-CLIPViT-L/14@336pxViT-L/14407MRoBERTa-wwm-Base102M336CN-CLIPViT-H/14ViT-H/14958MRoBERTa-wwm-Large326M224 原来都已经是大炮打麻雀了,那么本类验证码我们用的便是 CN-CLIPRN50 作为预训练 ckpt 来进行训练!
环境准备

本地环境


没有 GPU 的同学可以采用往期文章推荐去租用 GPU 去训练,租用方法详细检察往期文章:【验证码辨认专栏】人均通杀点选验证码!Yolov5 + 孪生神经网络 or 图像分类 = 高精模型 。
AutoDL 版本环境


这里有坑点,硬盘最好泯灭个位数去扩容一下,因为你不能包管你全程不踩雷,某些操作不妥大概会导致服务器硬盘爆满,导致训练最后模型保存失败,内存不足等问题:

finetune

代码组织

工作目录如下,全文 ${DATAPATH} 将用 KG_finetune 取代:
  1. Chinese-CLIP/
  2. ├── run_scripts/
  3. │   ├── muge_finetune_vit-b-16_rbt-base.sh # 训练脚本,官方样例
  4. │   ├── flickr30k_finetune_vit-b-16_rbt-base.sh # 训练脚本,官方样例
  5. │  
  6. └── cn_clip/
  7.     ├── clip/
  8.     ├── eval/
  9.     ├── preprocess/
  10.     └── training/
  11. ${DATAPATH} # 作者为 KG_finetune
  12. ├── pretrained_weights/ # 预训练骨架
  13. ├── experiments/  # 训练模型导出地址
  14. ├── deploy/              # 用于存放 pt 转换 ONNX
  15. └── datasets/
  16.     ├── KG_GE/
复制代码
预训练 CKPT

上文我们谈到,我们选择 CN-CLIPRN50 骨架作为预训练模型,我们将 CN-CLIPRN50 下载到本地,然后将其移动到 pretrained_weights 目录下。
数据集预处理

CLIP 数据集与我们常见数据集不同,为了与 Chinese-CLIP 代码适配,同时包管数据处理和读取的服从,我们发起将训练 & 评测使用的图文数据集统一组织成如下的方式:
  1. ${DATAPATH} # 作者为TX_6icon
  2. └── datasets/
  3.     └── KG_GE/
  4.         ├── train_imgs.tsv      # 图片id & 图片内容
  5.         ├── train_texts.jsonl   # 文本id & 文本内容,连同匹配的图片id列表
  6.         ├── valid_imgs.tsv
  7.         ├── valid_texts.jsonl
  8.         ├── test_imgs.tsv
  9.         └── test_texts.jsonl
复制代码
图片不是以大量的小文件方式存放,而是将训练/验证/测试图片以 base64 情势分别存放在 ${split}_imgs.tsv 文件中。文件每行表现一张图片,包含图片 id(int 型)与图片 base64,以 tab 隔开,格式如下:
  1. 1000002        /9j/4AAQSkZJ...YQj7314oA//2Q==
复制代码
当然也给各人写好了完整的代码,只需将待标注图片放到指定文件夹,运行脚本,即可完成转换,即可天生 train_imgs.tsv,val_imgs.tsv,test_imgs.tsv。完整代码如下:
  1. import os
  2. import random
  3. import base64
  4. from PIL import Image
  5. from io import BytesIO
  6. from sklearn.model_selection import train_test_split
  7. def image_to_base64(file_path):
  8.     # Convert image to base64 string
  9.     with Image.open(file_path) as img:
  10.         img_buffer = BytesIO()
  11.         img.save(img_buffer, format=img.format)
  12.         byte_data = img_buffer.getvalue()
  13.         base64_str = base64.b64encode(byte_data).decode('utf-8')
  14.         return base64_str
  15. def generate_random_id(length=10):
  16.     # Generate a random number with the specified number of digits
  17.     return ''.join([str(random.randint(1, 9)) for _ in range(length)])
  18. def save_images_to_split_tsv(image_dir, output_dir, train_ratio=0.8, val_ratio=0.1, test_ratio=0.1, id_length=15):
  19.     # 获取所有图片文件
  20.     image_files = os.listdir(image_dir)
  21.     # 随机分成训练集、验证集和测试集
  22.     train_files, test_files = train_test_split(image_files, test_size=test_ratio)
  23.     train_files, val_files = train_test_split(train_files, test_size=val_ratio / (train_ratio + val_ratio))
  24.     # 保存到不同的TSV文件中
  25.     save_images_to_tsv(train_files, os.path.join(output_dir, 'train_imgs.tsv'), image_dir, id_length)
  26.     save_images_to_tsv(val_files, os.path.join(output_dir, 'val_imgs.tsv'), image_dir, id_length)
  27.     save_images_to_tsv(test_files, os.path.join(output_dir, 'test_imgs.tsv'), image_dir, id_length)
  28. def save_images_to_tsv(image_files, output_file, image_dir, id_length):
  29.     with open(output_file, 'w') as f_out:
  30.         for file_name in image_files:
  31.             file_path = os.path.join(image_dir, file_name)
  32.             image_id = generate_random_id(id_length)
  33.             try:
  34.                 base64_str = image_to_base64(file_path)
  35.                 f_out.write(f"{image_id}\t{base64_str}\n")
  36.             except Exception as e:
  37.                 print(f"Error processing {file_name}: {e}")
  38. # Example usage
  39. image_directory = 'img'
  40. output_directory = 'datasets'
  41. save_images_to_split_tsv(image_directory, output_directory)
复制代码
训练集/验证集/测试集比例这里推荐 0.9:0.1:0.1,运行后将会在当前目录天生所需文件,文件内格式如下:

文本信息及图文对匹配关系则保存在 ${split}_texts.jsonl 文件。文件每行是一行 json,格式如下:
  1. {"text_id": 8428, "text": "高级感托特包斜挎", "image_ids": [1076345, 517602]}
复制代码
对于测试集只有文本,不知道图文对匹配关系的情况,每行的 image_ids 字段处理为空列表即可,即 "image_ids": []。
所以这种数据集格式就和我们平台所见不同,必要将指定 id,放到所匹配的 text_id 中,所以标注就有点困难,这里也提供了专属的标注工具:

支持断点续标,标注词记忆,全部图片完成标注后将会在当前目录天生我们所需的数据集格式。
最后,我们还必要将 tsv 和 jsonl 文件一起序列化,转换为内存索引的 LMDB 数据库文件,方便训练时的随机读取 ,命令如下:
  1. python cn_clip/preprocess/build_lmdb_dataset.py \
  2.     --data_dir ${DATAPATH}/datasets/${dataset_name}
  3.     --splits train,valid,test
复制代码
这部门转换我们在后续将全部准备工作完成后,将代码打包上传到 GPU 服务器再进行执行。
例如对于 KG_GE 数据集,则 ${dataset_name} 设为 KG_GE,--splits 指定必要转换的数据集分别,以逗号不加空格分隔。转换后,数据集文件夹下会对应增长以下 LMDB 序列化文件 ,格式如下:
  1. ${DATAPATH}
  2. └── datasets/
  3.     └── ${dataset_name}/
  4.         └── lmdb/
  5.             ├── train
  6.             │   ├── imgs
  7.             │   └── pairs
  8.             ├── valid
  9.             └── test
复制代码
模型微调

前面的步骤,我们已经将数据集准备完毕,接下来我们开始训练的部门,必要我们参考样例,手写一个训练脚本,这里我们举例几个告急的配置文件来讲:
  1. WORKER_CNT: 训练的机器个数,一般都是单机器,写1就行
  2. GPUS_PER_NODE: 每个机器上的GPU个数,大部分为1,具体查询自己的gpu个数
  3. 训练/验证数据
  4. train-data: 训练数据LMDB目录
  5. val-data: 验证数据LMDB目录
  6. num-workers: 训练集数据处理
  7. valid-num-workers: 验证集数据处理(DataLoader)的进程数,默认为1。
  8. 训练超参数
  9. vision-model: 这里选择 RN50
  10. text-model: 参考骨架对应,我们选择 RBT3-chinese
  11. context-length: 文本输入序列长度。
  12. warmup: warmup步数。
  13. batch-size: 训练时单卡batch-size。
  14. lr: 学习率。
  15. wd: weight decay。
  16. max-steps: 训练步数,也可通过max-epochs指定训练轮数。
  17. valid-batch-size: 验证时单机batch-size。
  18. 输出选项
  19. name: 指定输出路径。超参日志, 训练日志以及产出ckpt均会存放至 ${DATAPATH}/experiments/${name}/。
  20. save-step-frequency及save-epoch-frequency: 存ckpt的步数或轮数间隔。
  21. report-training-batch-acc: 日志是否报告训练图到文&文到图batch准确率。
  22. 权重读取相关选项
  23. resume: 权重读取的路径。预训练骨架
复制代码
这里给出我的训练脚本,如下:
  1. #!/usr/bin/env
  2. # Guide:
  3. # This script supports distributed training on multi-gpu workers (as well as single-worker training).
  4. # Please set the options below according to the comments.
  5. # For multi-gpu workers training, these options should be manually set for each worker.
  6. # After setting the options, please run the script on each worker.
  7. # Command: bash run_scripts/muge_finetune_vit-b-16_rbt-base.sh ${DATAPATH}
  8. # Number of GPUs per GPU worker
  9. GPUS_PER_NODE=1
  10. # Number of GPU workers, for single-worker training, please set to 1
  11. WORKER_CNT=1
  12. # The ip address of the rank-0 worker, for single-worker training, please set to localhost
  13. export MASTER_ADDR=localhost
  14. # The port for communication
  15. export MASTER_PORT=8514
  16. # The rank of this worker, should be in {0, ..., WORKER_CNT-1}, for single-worker training, please set to 0
  17. export RANK=0
  18. export PYTHONPATH=${PYTHONPATH}:`pwd`/cn_clip/
  19. DATAPATH=${1}
  20. # data options
  21. train_data=${DATAPATH}/datasets/KG_GE/lmdb/train
  22. val_data=${DATAPATH}/datasets/KG_GE/lmdb/valid # if val_data is not specified, the validation will be automatically disabled
  23. # restore options
  24. resume=${DATAPATH}/pretrained_weights/clip_cn_rn50.pt # or specify your customed ckpt path to resume
  25. reset_data_offset="--reset-data-offset"
  26. reset_optimizer="--reset-optimizer"
  27. # reset_optimizer=""
  28. # output options
  29. output_base_dir=${DATAPATH}/experiments/
  30. name=txmuge_rs50
  31. save_step_frequency=999999 # disable it
  32. save_epoch_frequency=1
  33. log_interval=1
  34. report_training_batch_acc="--report-training-batch-acc"
  35. # report_training_batch_acc=""
  36. # training hyper-params
  37. context_length=52
  38. warmup=100
  39. batch_size=128
  40. valid_batch_size=20
  41. accum_freq=1
  42. lr=5e-5
  43. wd=0.001
  44. max_epochs=150 # or you can alternatively specify --max-steps
  45. valid_step_interval=20
  46. valid_epoch_interval=1
  47. vision_model=RN50
  48. text_model=RBT3-chinese
  49. use_augment="--use-augment"
  50. # use_augment=""
  51. python3 -m torch.distributed.launch --use_env --nproc_per_node=${GPUS_PER_NODE} --nnodes=${WORKER_CNT} --node_rank=${RANK} \
  52.           --master_addr=${MASTER_ADDR} --master_port=${MASTER_PORT} cn_clip/training/main.py \
  53.           --train-data=${train_data} \
  54.           --val-data=${val_data} \
  55.           --resume=${resume} \
  56.           ${reset_data_offset} \
  57.           ${reset_optimizer} \
  58.           --logs=${output_base_dir} \
  59.           --name=${name} \
  60.           --save-step-frequency=${save_step_frequency} \
  61.           --save-epoch-frequency=${save_epoch_frequency} \
  62.           --log-interval=${log_interval} \
  63.           ${report_training_batch_acc} \
  64.           --context-length=${context_length} \
  65.           --warmup=${warmup} \
  66.           --batch-size=${batch_size} \
  67.           --valid-batch-size=${valid_batch_size} \
  68.           --valid-step-interval=${valid_step_interval} \
  69.           --valid-epoch-interval=${valid_epoch_interval} \
  70.           --accum-freq=${accum_freq} \
  71.           --lr=${lr} \
  72.           --wd=${wd} \
  73.           --max-epochs=${max_epochs} \
  74.           --vision-model=${vision_model} \
  75.           ${use_augment} \
  76.           --text-model=${text_model}
复制代码
我们在 run_scripts 文件夹新建一个 sh 脚本文件,将上面训练脚本复制进去,详细参数按个人习惯进行修改。
此脚本我们用的就是 RN50 作为预训练模型进行训练的。
train

我们在本地将所需文件全部准备好以后,按下面的格式压缩成压缩包,压缩包内容为俩个文件夹,分别是 Chinese-CLIP 与 TX_6icon:
  1. Chinese-CLIP/
  2. ├── run_scripts/
  3. │   ├── muge_finetune_vit-b-16_rbt-base.sh
  4. │   ├── flickr30k_finetune_vit-b-16_rbt-base.sh
  5. │  
  6. └── cn_clip/
  7.     ├── clip/
  8.     ├── eval/
  9.     ├── preprocess/
  10.     └── training/
  11. TX_6icon #作者为TX_6icon
  12. ├── pretrained_weights/
  13. ├── experiments/  
  14. ├── deploy/             
  15. └── datasets/
  16.     ├── KG_GE/
复制代码
进入 GPU 训练平台,这里有一个暗坑,我们必要选择数据盘,万万不要选择其他地方:

将我们的压缩包传到此处,最终如下:

进入 cd Chinese-CLIP,我们上文说的命令现在进行执行 python3 cn_clip/preprocess/build_lmdb_dataset.py --data_dir /root/autodl-tmp/TX_6icon/datasets/KG_GE --splits train,valid,test 。
结果如下:

紧接着进入 run_scripts 中,新建一个 tx_rs50_rbt-base.sh 脚本,将我们上面的训练脚本复制进去并保存!
紧接着回到 root@autodl-container-d4594a8753-96d5e6b4:~/autodl-tmp/Chinese-CLIP#  中执行命令:
  1. bash run_scripts/tx_rs50_rbt-base.sh /root/autodl-tmp/TX_6icon
复制代码
如许我们的训练代码就跑起来了,如下:

最终导出的模型会在 experiments 文件夹中,取决于我们刚刚写的训练脚本内里的目录是怎样的:
  1. output_base_dir=${DATAPATH}/experiments/
  2. name=txmuge_rs50
复制代码
则我的模型文件导出则在 experiments 下的 txmuge_rs50 中,如下:

onnx 转换

最新的 Chinese-CLIP 代码,已支持将各规模的 Pytorch 模型,转换为 onnx 模型。

这里有个暗坑,选择 GPU 平台去训练的同学这里必要降级 Pytorch,命令如下:
  1. pip install torch==1.13.1 torchvision==0.14.1 torchaudio==0.13.1 --index-url https://download.pytorch.org/whl/cu117
复制代码
将 pt 模型转换 onnx 同时也必要我们编写 sh 脚本,由于我们开始整理结构的时候文件目录就已经创好,所以 mkdir -p /root/autodl-tmp/TX_6icon/deploy/ 命令就是多余的,我的 onnx.sh 脚本如下:
  1. #cd Chinese-CLIP/
  2. export CUDA_VISIBLE_DEVICES=0
  3. export PYTHONPATH=${PYTHONPATH}:`pwd`/cn_clip
  4. # ${DATAPATH}的指定,请参考Readme"代码组织"部分创建好目录,尽量使用相对路径:https://github.com/OFA-Sys/Chinese-CLIP#代码组织
  5. checkpoint_path=/root/epoch_latest.pt # 指定要转换的ckpt完整路径
  6. #mkdir -p /root/autodl-tmp/TX_6icon/deploy/ # 创建ONNX模型的输出文件夹
  7. python cn_clip/deploy/pytorch_to_onnx.py \
  8.        --model-arch RN50 \
  9.        --pytorch-ckpt-path ${checkpoint_path} \
  10.        --save-onnx-path /root/autodl-tmp/TX_6icon/deploy/tx666 \
  11.        --convert-text --convert-vision
复制代码
如果不降级 Pytorch 大概会出现如下错误,只需按上面要求将 torch 版本降低即可。
最终 onnx 转换完毕提示如下则为乐成,即可在 deploy 文件下找到我们乐成转换的 onnx 文件:
  1. Finished PyTorch to ONNX conversion...
  2. >>> The text FP32 ONNX model is saved at ${DATAPATH}/deploy/vit-b-16.txt.fp32.onnx
  3. >>> The text FP16 ONNX model is saved at ${DATAPATH}/deploy/vit-b-16.txt.fp16.onnx with extra file ${DATAPATH}/deploy/vit-b-16.txt.fp16.onnx.extra_file
  4. >>> The vision FP32 ONNX model is saved at ${DATAPATH}/deploy/vit-b-16.img.fp32.onnx
  5. >>> The vision FP16 ONNX model is saved at ${DATAPATH}/deploy/vit-b-16.img.fp16.onnx with extra file ${DATAPATH}/deploy/vit-b-16.img.fp16.onnx.extra_file
复制代码
然后将与 fp16 有关的 4 个模型文件全部导出: tx666.img.fp16.onnx,tx666.img.fp16.onnx.extra_file ,tx666.txt.fp16.onnx,tx666.txt.fp16.onnx.extra_file。
推理摆设

提取图像/文本特征/相似度比较:
  1. # 完成必要的import(下文省略)
  2. import onnxruntime
  3. from PIL import Image
  4. import numpy as np
  5. import torch
  6. import argparse
  7. import cn_clip.clip as clip
  8. from clip import load_from_name, available_models
  9. from clip.utils import _MODELS, _MODEL_INFO, _download, available_models, create_model, image_transform
  10. DIR_PATH = pathlib.Path(__file__).parent.as_posix()
  11. img_sess_options = onnxruntime.SessionOptions()
  12. img_sess_options.intra_op_num_threads = 8
  13. img_sess_options.inter_op_num_threads = 4
  14. img_onnx_model_path = f'{DIR_PATH}/cn_clip/deploy/tx666.img.fp16.onnx'
  15. img_session = onnxruntime.InferenceSession(img_onnx_model_path, sess_options=img_sess_options,
  16.                                            providers=["CUDAExecutionProvider"])
  17. model_arch = "RN50"
  18. preprocess = image_transform(_MODEL_INFO[model_arch]['input_resolution'])
  19. txt_sess_options = onnxruntime.SessionOptions()
  20. txt_sess_options.intra_op_num_threads = 8
  21. txt_sess_options.inter_op_num_threads = 4
  22. txt_onnx_model_path = f'{DIR_PATH}/cn_clip/deploy/tx666.txt.fp16.onnx'
  23. txt_session = onnxruntime.InferenceSession(txt_onnx_model_path, sess_options=txt_sess_options,
  24.                                            providers=["CUDAExecutionProvider"])
复制代码
由于训练机器和本机 TF 环境大概不同,预测函数我们要略加修改:
  1. def calculate_matching_probability(text: str, images: Image.Image) -> float:
  2.     image = preprocess(images)
  3.     if isinstance(image, np.ndarray):
  4.         image = np.expand_dims(image.astype(np.float32), axis=0)
  5.     elif isinstance(image, torch.Tensor):
  6.         image = image.float().unsqueeze(0).cpu().numpy()
  7.     else:
  8.         raise ValueError("Unsupported image format. Expected a numpy array or torch tensor.")
  9.     image_features = img_session.run(["unnorm_image_features"], {"image": image})[0]
  10.     image_features /= np.linalg.norm(image_features, axis=-1, keepdims=True)
  11.     text_tokens = clip.tokenize(["K哥爬虫", text], context_length=52)
  12.     text_features = []
  13.     for one_text in text_tokens:
  14.         one_text = np.expand_dims(one_text, axis=0)
  15.         text_feature = txt_session.run(["unnorm_text_features"], {"text": one_text})[0]
  16.         text_features.append(text_feature)
  17.     text_features = np.vstack(text_features)
  18.     text_features /= np.linalg.norm(text_features, axis=1, keepdims=True)
  19.     logits_per_image = 100 * np.dot(image_features, text_features.T)
  20.     probabilities = np.exp(logits_per_image - np.max(logits_per_image)) / np.sum(
  21.         np.exp(logits_per_image - np.max(logits_per_image)), axis=-1, keepdims=True)
  22.     return probabilities[0][1]
复制代码
因为 CLIP 是图像与多个文本进行对比,找出最优,所以我们在匹配答案的时候必要随机一个字符串,以便模型可以正确比较,text_tokens = clip.tokenize(["K哥爬虫", text], context_length=52)。
最终,通过比较找出相似度最优解,对比算法可以自行去编写,可以设置一个相似度阈值,将凌驾该部门的答案乐成匹配即可,这部门算法文章开头已经说过,星球成员可以私信领取,运行结果如下:

最终也是得到了我们必要的坐标 [1, 2]。
当然除了原图辨认以外,也可以基于这个思路去开发截图辨认,无非就是接收参数由一个文本 + 图像,变成了只传入一张截图进行辨认,思路稳固,可以使用飞浆等框架进行题目的分割与辨认,最终还是要回归到相似度图文相似度比较。
结果展示

GPU 环境下,6 图速度根本维持毫秒级别,结果如下:

雷区(基于 GPU 训练平台)


  1. if isinstance(image, np.ndarray):
  2.          image = np.expand_dims(image.astype(np.float32), axis=0)
  3. elif isinstance(image, torch.Tensor):
  4.          image = image.float().unsqueeze(0).cpu().numpy()
复制代码


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 qidao123.com技术社区-IT企服评测·应用市场 (https://dis.qidao123.com/) Powered by Discuz! X3.4