首页 游戏 软件 资讯 排行榜 专题
首页
AI
【AI达人特训营第三期】基于PPYOLO实现抽烟检测全流程

【AI达人特训营第三期】基于PPYOLO实现抽烟检测全流程

热心网友
95
转载
2025-07-24
本文介绍基于PaddleDetection的PPYOLO实现抽烟检测全流程。先介绍PPYOLO模型结构,包括骨干、颈部和头部及优化点。接着说明数据集准备,涉及数据说明、标注、处理(解压、格式转换等)。还涵盖模型训练、评估、预测及部署的步骤与结果,评估mAP达61.21%。

【ai达人特训营第三期】基于ppyolo实现抽烟检测全流程 - 游乐网

PaddleDetection:基于PPYOLO实现抽烟检测全流程

1. 模型介绍

ppyolo是PaddleDetection开源的yolo系列模型PP-YOLO的整体结构图如下:【AI达人特训营第三期】基于PPYOLO实现抽烟检测全流程 - 游乐网        

免费影视、动漫、音乐、游戏、小说资源长期稳定更新! 👉 点此立即查看 👈

YOLO检测器分为三个主要部分。

YOLO Backbone:YOLO Backbone(骨干)是一个卷积神经网络,它将图像像素合并在一起以形成不同粒度的特征。骨干通常在分类数据集(通常为ImageNet)上进行预训练。ppyolo使用Resnet50-vd-dcn ConvNet骨干替换YOLOv3 Darknet53骨干,它的执行优化了更多的框架,并且其参数少于Darknet53。通过交换Backbone,ppyolo的mAP的取得一定的提升。

YOLO Neck:ppyoloYOLO采取的是FPN特征金字塔结构做一个特征融合,类似Yolo3,选取最后三个卷积层C3, C4,C5,然后经过FPN结构在传递到预测头之前,将ConvNet图层表示的高层级语义信息和低层级信息进行融合。

YOLO Head:检测头是网络中进行边界框和类预测的部分,它由关于类,框和对象的三个YOLO损失函数指导。原始yolo3的检测头是一个非常简单的结构,通过3x3卷积并最后用1x1卷积调整到自己所需要的通道数目。

在数据增广仅靠mixup的条件下,通过合理的tricks组合,例如使用更大的batchsize192,8GPUs * 24(pre gpu)、Matrix NMS、CoordConv等方法对yolov3进一步优化和改进,最终在COCOtest-dev2017数据集上精度达到45.9%,在单卡V100上FP32推理速度为72.9 FPS。与其他模型对比如下: 【AI达人特训营第三期】基于PPYOLO实现抽烟检测全流程 - 游乐网        

2. PPYOLO数据集准备

2.1 数据说明

原始数据下载链接:https://data.mendeley.com/datasets/7b52hhzs3r/1

该数据集共包含2400张原始图像,其中1200张属于吸烟(吸烟者)类别,其余1200张属于禁烟(非吸烟者)类别。该数据集是通过扫描各种搜索引擎来整理的,输入多个关键词,包括吸烟、吸烟者、人、咳嗽、服用吸入器、打电话的人、饮用水等。为了更好地训练模型,我们试图在两个类别中考虑多功能图像,以产生一定程度的类别间混乱。例如,吸烟类别由多个角度和各种姿势的吸烟者图像组成。此外,不吸烟类别中的图像包含非吸烟者的图像,其手势与吸烟图像稍相似,例如人们喝水、使用吸入器、拿着手机、咬指甲等。未来的研究人员可以使用该数据集提出机器学习算法,用于自动检测和筛查吸烟者,以确保绿色环境并在智能城市中进行监测。

2.2 数据标注

原数据已经对smoking、notsmoking进行了分类,故可使用分类模型完成此次任务。为了体验PaddleDetection的yolo系类模型训练、部署的过程,在本地使用LabelImg对smoking数据进行标注。标注好的数据集已经上传,链接:https://aistudio.baidu.com/aistudio/datasetdetail/198887 ,欢迎下载使用。数据集里居然有树哥!!【AI达人特训营第三期】基于PPYOLO实现抽烟检测全流程 - 游乐网        

2.3 数据处理

写在前: 数据清洗的重要性!!! 在数据预处理的时候发现奇怪的报错,cv2.imread()报错,经过一系列的操作发现有jpg图片实际格式为gif,大无语。最后发现以下图片存在问题,直接删除。 training_data/smoking/smoking_0687.webp 图片实际格式为gif validation_data/smoking/smoking_0702.webp 图片实际格式为gif training_data/smoking/smoking_0094.webp 图片实际类别为notsmoking

源数据压缩包格式为RAR,标注数据集压缩包为zip

2.3.1 解压数据集

解压数据集并移动到work目录,构建训练数据集文件

In [ ]
# 安装 unrar package# !pip install --upgrade pip# !pip install unrar# !unzip  /home/aistudio/data/data198887/7b52hhzs3r-1.zip# !mv smokingVSnotsmoking.rar /home/aistudio/work# %cd /home/aistudio/work # !rar x smokingVSnotsmoking.rar!pwd!unzip /home/aistudio/data/data198887/smokingVSnotsmoking_mark.zip -d /home/aistudio/work
登录后复制    In [6]
import osimport numpy as npimport matplotlib.pyplot as pltimport globimport shutilimport tqdm# 创建多级文件路径:./smoke_data/images/train, ./smoke_data/images/val, ./smoke_data/labels/train, ./smoke_data/labels/valif not os.path.exists('./smoke_data'):    os.mkdir('./smoke_data')if not os.path.exists('./smoke_data/images'):    os.mkdir('./smoke_data/images')if not os.path.exists('./smoke_data/images/train'):    os.mkdir('./smoke_data/images/train')if not os.path.exists('./smoke_data/images/val'):    os.mkdir('./smoke_data/images/val')if not os.path.exists('./smoke_data/labels'):    os.mkdir('./smoke_data/labels')if not os.path.exists('./smoke_data/labels/train'):    os.mkdir('./smoke_data/labels/train')if not os.path.exists('./smoke_data/labels/val'):    os.mkdir('./smoke_data1/labels/val')# 检查文件结构! tree ./smoke_data1
登录后复制        
./smoke_data1├── images│   ├── train│   └── val└── labels    ├── train    └── val6 directories, 0 files
登录后复制        In [4]
%cd /home/aistudio/work/!cp -rf ./dataset/training_data/smoking/* ./smoke_data/images/train!cp ./dataset/training_data/lable/smoking* ./smoke_data/labels/train!cp -rf ./dataset/validation_data/smoking/* ./smoke_data/images/val!cp ./dataset/validation_data/lable/smoking* ./smoke_data/labels/valprint('train_img_file_names:', len(os.listdir('./smoke_data/images/train')))print('train_label_file_names:', len(os.listdir('./smoke_data/labels/train')))print('val_img_file_names:', len(os.listdir('./smoke_data/images/val')))print('val_label_file_names:', len(os.listdir('./smoke_data/labels/val')))
登录后复制        
/home/aistudio/worktrain_img_file_names: 803train_label_file_names: 803val_img_file_names: 200val_label_file_names: 200
登录后复制        

2.3.2 yolo数据集格式转voc格式

标注的时候按照yolo数据集格式进行标注的,训练的时候发现只有coco、voc两种格式,只能转一下喽!!!

In [28]
from xml.dom.minidom import Documentimport osimport cv2 # def makexml(txtPath, xmlPath, picPath):  # txt所在文件夹路径,xml文件保存路径,图片所在文件夹路径def makexml(picPath, txtPath, xmlPath):  # txt所在文件夹路径,xml文件保存路径,图片所在文件夹路径    """此函数用于将yolo格式txt标注文件转换为voc格式xml标注文件    在自己的标注图片文件夹下建三个子文件夹,分别命名为picture、txt、xml    """    # font_lib 这里的字库格式可以根据你的实际格式来读取匹配    # font_lib = open("./label_list.txt", "r", encoding="utf8").read().split("\n")    dic = {'0': "smoking",  # 创建字典用来对类型进行转换        #    '1': "数据集标签类别",  # 此处的字典要与自己的classes.txt文件中的类对应,且顺序要一致        }    files = os.listdir(txtPath)    for i, name in enumerate(files):        xmlBuilder = Document()        annotation = xmlBuilder.createElement("annotation")  # 创建annotation标签        xmlBuilder.appendChild(annotation)        txtFile = open(txtPath + name)        txtList = txtFile.readlines()        img = cv2.imread(picPath + name[0:-4] + ".webp")        # print(picPath + name[0:-4] + ".webp")        Pheight, Pwidth, Pdepth = img.shape         folder = xmlBuilder.createElement("folder")  # folder标签        foldercontent = xmlBuilder.createTextNode("smoking")        folder.appendChild(foldercontent)        annotation.appendChild(folder)  # folder标签结束         filename = xmlBuilder.createElement("filename")  # filename标签        filenamecontent = xmlBuilder.createTextNode(name[0:-4] + ".webp")        filename.appendChild(filenamecontent)        annotation.appendChild(filename)  # filename标签结束        folder = xmlBuilder.createElement("path")  # path标签         foldercontent = xmlBuilder.createTextNode(picPath + name[0:-4] + ".webp")        folder.appendChild(foldercontent)        annotation.appendChild(folder)  # path标签结束        size = xmlBuilder.createElement("size")  # size标签        width = xmlBuilder.createElement("width")  # size子标签width        widthcontent = xmlBuilder.createTextNode(str(Pwidth))        width.appendChild(widthcontent)        size.appendChild(width)  # size子标签width结束         height = xmlBuilder.createElement("height")  # size子标签height        heightcontent = xmlBuilder.createTextNode(str(Pheight))        height.appendChild(heightcontent)        size.appendChild(height)  # size子标签height结束         depth = xmlBuilder.createElement("depth")  # size子标签depth        depthcontent = xmlBuilder.createTextNode(str(Pdepth))        depth.appendChild(depthcontent)        size.appendChild(depth)  # size子标签depth结束         annotation.appendChild(size)  # size标签结束         for j in txtList:            oneline = j.strip().split(" ")            object = xmlBuilder.createElement("object")  # object 标签            picname = xmlBuilder.createElement("name")  # name标签#             print(oneline[0])            namecontent = xmlBuilder.createTextNode(dic[str((oneline[0]))])            picname.appendChild(namecontent)            object.appendChild(picname)  # name标签结束             pose = xmlBuilder.createElement("pose")  # pose标签            posecontent = xmlBuilder.createTextNode("Unspecified")            pose.appendChild(posecontent)            object.appendChild(pose)  # pose标签结束             truncated = xmlBuilder.createElement("truncated")  # truncated标签            truncatedContent = xmlBuilder.createTextNode("0")            truncated.appendChild(truncatedContent)            object.appendChild(truncated)  # truncated标签结束             difficult = xmlBuilder.createElement("difficult")  # difficult标签            difficultcontent = xmlBuilder.createTextNode("0")            difficult.appendChild(difficultcontent)            object.appendChild(difficult)  # difficult标签结束             bndbox = xmlBuilder.createElement("bndbox")  # bndbox标签            xmin = xmlBuilder.createElement("xmin")  # xmin标签            mathData = int(((float(oneline[1])) * Pwidth + 1) - (float(oneline[3])) * 0.5 * Pwidth)            xminContent = xmlBuilder.createTextNode(str(mathData))            xmin.appendChild(xminContent)            bndbox.appendChild(xmin)  # xmin标签结束             ymin = xmlBuilder.createElement("ymin")  # ymin标签            mathData = int(((float(oneline[2])) * Pheight + 1) - (float(oneline[4])) * 0.5 * Pheight)            yminContent = xmlBuilder.createTextNode(str(mathData))            ymin.appendChild(yminContent)            bndbox.appendChild(ymin)  # ymin标签结束             xmax = xmlBuilder.createElement("xmax")  # xmax标签            mathData = int(((float(oneline[1])) * Pwidth + 1) + (float(oneline[3])) * 0.5 * Pwidth)            xmaxContent = xmlBuilder.createTextNode(str(mathData))            xmax.appendChild(xmaxContent)            bndbox.appendChild(xmax)  # xmax标签结束             ymax = xmlBuilder.createElement("ymax")  # ymax标签            mathData = int(((float(oneline[2])) * Pheight + 1) + (float(oneline[4])) * 0.5 * Pheight)            ymaxContent = xmlBuilder.createTextNode(str(mathData))            ymax.appendChild(ymaxContent)            bndbox.appendChild(ymax)  # ymax标签结束             object.appendChild(bndbox)  # bndbox标签结束             annotation.appendChild(object)  # object标签结束         f = open(xmlPath + name[0:-4] + ".xml", 'w')        xmlBuilder.writexml(f, indent='\t', newl='\n', addindent='\t', encoding='utf-8')        f.close() if __name__ == "__main__":    if not os.path.exists('/home/aistudio/work/dataset/training_data/annotations'):        os.makedirs("/home/aistudio/work/dataset/training_data/annotations")    picPath = "/home/aistudio/work/dataset/training_data/smoking/" # 图片所在文件夹路径,后面的/一定要带上    txtPath = "/home/aistudio/work/dataset/training_data/lable/"  # 标签txt所在文件夹路径,后面的/一定要带上    xmlPath = "/home/aistudio/work/dataset/training_data/annotations/"  # xml文件保存路径,后面的/一定要带上    makexml(picPath, txtPath, xmlPath)    if not os.path.exists('/home/aistudio/work/dataset/validation_data/annotations'):        os.makedirs("/home/aistudio/work/dataset/validation_data/annotations")    picPath = "/home/aistudio/work/dataset/validation_data/smoking/" # 图片所在文件夹路径,后面的/一定要带上    txtPath = "/home/aistudio/work/dataset/validation_data/lable/"  # 标签txt所在文件夹路径,后面的/一定要带上    xmlPath = "/home/aistudio/work/dataset/validation_data/annotations/"  # xml文件保存路径,后面的/一定要带上    makexml(picPath, txtPath, xmlPath)
登录后复制    

2.3.3 生成训练集、测试集、验证集、标签文档

In [35]
train_f = open('/home/aistudio/work/smoke_data_voc/train.txt','w')   # 生成训练文件val_f = open('/home/aistudio/work/smoke_data_voc/val.txt' ,'w')    # 生成验证文件text_f = open('/home/aistudio/work/smoke_data_voc/test.txt' ,'w')  # 生成验证文件root_dir  = '/home/aistudio/work/smoke_data_voc/'   # 根目录train_dir = root_dir + 'training_data/'             # 训练集路径val_dir = root_dir + 'validation_data/'             # 验证集路径验证test_dir = root_dir + 'testing_data/'               # 测试集路径dir_dic = {train_dir:train_f, val_dir:val_f}for data_dir, file_dir in dir_dic.items():    path_list = list()    for img in os.listdir(data_dir + 'smoking'):        img_path = os.path.join(data_dir + 'smoking',img)        xml_path = os.path.join(data_dir + 'annotations',img.replace('jpg', 'xml'))        path_list.append((img_path, xml_path))    for i ,content in enumerate(path_list):        img, xml = content        text = img + ' ' + xml + '\n'        file_dir.write(text)    file_dir.close()# 生成测试集txt文件path_list = list()for img in os.listdir(test_dir):    img_path = os.path.join(data_dir,img)    path_list.append((img_path))for i ,content in enumerate(path_list):    img = content    text = img + '\n'    text_f.write(text)text_f.close()#生成标签文档label = ['smoking']#设置你想检测的类别with open(root_dir + '/label_list.txt', 'w') as f:    for text in label:        f.write(text+'\n')
登录后复制    

3. 模型训练

3.1 下载PaddleDetection,安装相关依赖

In [ ]
# 安装依赖# !git clone https://gitee.com/paddlepaddle/PaddleDetection.git -b release/2.6%cd /home/aistudio/work/PaddleDetection!pip install --upgrade pip!pip install --user -r requirements.txt
登录后复制    

3.2 配置文件

文件配置说明链接:https://github.com/PaddlePaddle/PaddleDetection/blob/release/2.5/docs/tutorials/configannotation 使用Paddle训练模型需要对一系列所谓模块化的配置文件进行修改(当然使用最新给定的数据集应该可以一键训练),最新给出是coco数据集格式的修改说明,对于voc数据集主要修改如下: a. /PaddleDetection/configs/ppyolo/ppyolo_r50vd_dcn_voc.yml metric修改为VOC、修改迭代次数:epoch、学习率:base_lr、batch_size等超参; b. /PaddleDetection/configs/ppyolo/base/ppyolo_reader.yml 修改模型训练、评估、测试的batch_size c. /PaddleDetection/configs/datasets/voc.yml num_class设置成1、name修改为VOCDataSet、dataset_dir设置为对应数据集路径

单卡训练时间太长,这里使用了4卡训练,batch_size设置为24,epoch为583,base_lr修改0.0002。 可使用左侧可视化工具,VisualDL服务实进行训练可视化。【AI达人特训营第三期】基于PPYOLO实现抽烟检测全流程 - 游乐网        

3.3 使用V100四卡进行训练

命令行加入 --use_vdl=True --vdl_log_dir="./output" 指定VisualDL的日志路径

In [ ]
# 使用ppyolo模型训练!export CUDA_VISIBLE_DEVICES=0,1,2,3# !python tools/train.py -c ./configs/ppyolo/ppyolo_r50vd_dcn_voc.yml --eval --use_vdl=True --vdl_log_dir="./output"!python -m paddle.distributed.launch --gpus 0,1,2,3 tools/train.py -c ./configs/ppyolo/ppyolo_r50vd_dcn_voc.yml --eval --use_vdl=True --vdl_log_dir="./output"
登录后复制    

4. 模型评估

PaddleDetection也提供了tools/eval.py脚本用于评估模型,评估是可以通过-o weights=指定待评估权重。 PaddleDetection训练时添加命令 --eval,会将所有checkpoint中评估结果最好的checkpoint保存为best_model.pdparams,可以看到评估结果mAP(0.50, 11point)为 61.21%。

In [19]
# 模型评估%cd /home/aistudio/work/PaddleDetection!python -u tools/eval.py \-c ./configs/ppyolo/ppyolo_r50vd_dcn_voc.yml \-o weights=./output/ppyolo_r50vd_dcn_voc/model_final
登录后复制        
/home/aistudio/work/PaddleDetection/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/matplotlib/__init__.py:107: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working  from collections import MutableMapping/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/matplotlib/rcsetup.py:20: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working  from collections import Iterable, Mapping/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/matplotlib/colors.py:53: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working  from collections import SizedWarning: import ppdet from source directory without installing, run 'python setup.py install' to install ppdet firstlyW0318 22:58:55.481233  9434 gpu_context.cc:244] Please NOTE: device: 0, GPU Compute Capability: 7.0, Driver API Version: 11.2, Runtime API Version: 11.2W0318 22:58:55.486397  9434 gpu_context.cc:272] device: 0, cuDNN Version: 8.2.[03/18 22:59:01] ppdet.utils.checkpoint INFO: Finish loading model weights: ./output/ppyolo_r50vd_dcn_voc/model_final.pdparams[03/18 22:59:02] ppdet.engine INFO: Eval iter: 0[03/18 22:59:10] ppdet.metrics.metrics INFO: Accumulating evaluatation results...[03/18 22:59:10] ppdet.metrics.metrics INFO: mAP(0.50, 11point) = 61.21%[03/18 22:59:10] ppdet.engine INFO: Total sample number: 199, average FPS: 22.408059600797294
登录后复制        

5. 模型预测

In [15]
# 预测结果%cd /home/aistudio/work/PaddleDetection! python tools/infer.py -c ./configs/ppyolo/ppyolo_r50vd_dcn_voc.yml --infer_img=/home/aistudio/work/smoke_data_voc/testing_data/abc089.webp -o weights=/home/aistudio/work/PaddleDetection/output/ppyolo_r50vd_dcn_voc/model_final# 结果可视化import matplotlib.pyplot as pltimport cv2img = cv2.imread("/home/aistudio/work/PaddleDetection/output/abc089.webp")img_ = cv2.resize(img, (300,300));# plt.figure(figsize=(15, 15))plt.imshow(cv2.cvtColor(img_, cv2.COLOR_BGR2RGB))plt.show()
登录后复制        
登录后复制登录后复制                

6. 模型部署

6.1 模型导出

PaddleDetection提供了模型导出工具,导出pdmodel用于模型的部署推理

In [ ]
## 模型导出%cd /home/aistudio/work/PaddleDetection! python tools/export_model.py \    -c ./configs/ppyolo/ppyolo_r50vd_dcn_voc.yml \    -o weights=/home/aistudio/work/PaddleDetection/output/ppyolo_r50vd_dcn_voc/model_final.pdparams \    TestReader.inputs_def.image_shape=[3,608,608] \    --output_dir inference_model
登录后复制    

6.2 模型推理

In [18]
# 模型推理%cd /home/aistudio/work/PaddleDetection! python deploy/python/infer.py \    --model_dir=./output_inference/ppyolo_r50vd_dcn_voc \    --image_file=/home/aistudio/work/smoke_data_voc/testing_data/abc155.webp \    --device=GPU \    --thresh=0.2
登录后复制        
/home/aistudio/work/PaddleDetection-----------  Running Arguments -----------action_file: Nonebatch_size: 1camera_id: -1combine_method: nmscpu_threads: 1device: GPUenable_mkldnn: Falseenable_mkldnn_bfloat16: Falseimage_dir: Noneimage_file: /home/aistudio/work/smoke_data_voc/testing_data/abc155.webpmatch_metric: iosmatch_threshold: 0.6model_dir: ./output_inference/ppyolo_r50vd_dcn_vocoutput_dir: outputoverlap_ratio: [0.25, 0.25]random_pad: Falsereid_batch_size: 50reid_model_dir: Nonerun_benchmark: Falserun_mode: paddlesave_images: Truesave_mot_txt_per_img: Falsesave_mot_txts: Falsesave_results: Falsescaled: Falseslice_infer: Falseslice_size: [640, 640]threshold: 0.2tracker_config: Nonetrt_calib_mode: Falsetrt_max_shape: 1280trt_min_shape: 1trt_opt_shape: 640use_coco_category: Falseuse_dark: Trueuse_gpu: Falsevideo_file: Nonewindow_size: 50-----------------------------------------------------  Model Configuration -----------Model Arch: YOLOTransform Order: --transform op: Resize--transform op: NormalizeImage--transform op: Permute--------------------------------------------class_id:0, confidence:0.6626, left_top:[634.51,356.80],right_bottom:[811.03,490.34]save result to: output/abc155.webpTest iter 0------------------ Inference Time Info ----------------------total_time(ms): 2229.7, img_num: 1average latency time(ms): 2229.70, QPS: 0.448491preprocess_time(ms): 1642.30, inference_time(ms): 587.40, postprocess_time(ms): 0.00
登录后复制        In [20]
# 推理结果可视化import matplotlib.pyplot as pltimport cv2img = cv2.imread("/home/aistudio/work/PaddleDetection/output/abc155.webp")plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))plt.show()
登录后复制        
登录后复制登录后复制                
来源:https://www.php.cn/faq/1425635.html
免责声明: 游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。

相关攻略

Pywinrm,一个 Python 管理利器!
科技数码
Pywinrm,一个 Python 管理利器!

Pywinrm 通过Windows远程管理(WinRM)协议,让Python能够像操作本地一样执行远程Windows命令,真正打通了跨平台管理的最后一公里。 在混合IT环境中,Linux机器管理Wi

热心网友
04.07
全网炸了!5亿人用的Axios竟被投毒,你的密钥还保得住吗?
科技数码
全网炸了!5亿人用的Axios竟被投毒,你的密钥还保得住吗?

早些时候,聊过 Python 领域那场惊心动魄的供应链攻击。当时我就感叹,虽然我们 JavaScript 开发者对这类套路烂熟于心,但亲眼目睹这种规模的“投毒”还是头一次。 早些时候,聊过 Pyth

热心网友
04.07
Toga,一个超精简的 Python 项目!
科技数码
Toga,一个超精简的 Python 项目!

Toga 是 BeeWare 家族的核心成员,号称“写一次,跑遍所有平台”,而且用的是系统原生控件,不是那种一看就是网页套壳的界面 。 写了这么多年 Python,你是不是也想过:要是能一套代码跑

热心网友
04.07
Python 异常处理:别再用裸奔的 try 了
科技数码
Python 异常处理:别再用裸奔的 try 了

异常处理的核心:让错误在正确的地方被有效处理。正确的地方,就是别在底层就把异常吞了,也别在顶层还抛裸奔的 Exception。 异常处理写得好,半夜不用起来改 bug。1 你是不是也这么干过?tr

热心网友
04.07
OpenClaw如何自定义SKILL
AI
OpenClaw如何自定义SKILL

1 Skills机制概述 提起OpenClaw的Skills机制,不少人可能会把它想象成传统意义上的可执行插件。其实,它的内涵要更精妙一些。 简单说,Skills本质上是一套基于提示驱动的能力扩展机制。它并不是一个可以独立“跑”起来的程序模块,而是通过一份结构化描述文件(核心就是那个SKILL m

热心网友
04.07

最新APP

宝宝过生日
宝宝过生日
应用辅助 04-07
台球世界
台球世界
体育竞技 04-07
解绳子
解绳子
休闲益智 04-07
骑兵冲突
骑兵冲突
棋牌策略 04-07
三国真龙传
三国真龙传
角色扮演 04-07

热门推荐

美国SEC主席Paul Atkins证实:加密货币安全港提案已送交白宫审查
web3.0
美国SEC主席Paul Atkins证实:加密货币安全港提案已送交白宫审查

加密货币行业翘首以盼的监管里程碑,终于有了实质性进展。美国证券交易委员会(SEC)主席保罗·阿特金斯(Paul Atkins)近日证实,那份允许加密项目在早期获得注册豁免权的“安全港”框架提案,已经正式送抵白宫,进入了最终审查阶段。 在范德堡大学与区块链协会联合举办的数字资产峰会上,阿特金斯透露了这

热心网友
04.08
微策略Strategy报告:第一季录得144.6亿美元浮亏 再斥资约3.3亿美元买进4871枚比特币
web3.0
微策略Strategy报告:第一季录得144.6亿美元浮亏 再斥资约3.3亿美元买进4871枚比特币

微策略Strategy报告:第一季录得144 6亿美元浮亏 再斥资约3 3亿美元买进4871枚比特币 市场震荡的威力有多大?看看Strategy的最新季报就明白了。根据其最新向美国证管会(SEC)提交的8-K报告,受市场剧烈波动影响,这家公司所持的比特币在第一季度录得了一笔惊人的数字——144 6亿

热心网友
04.08
稳定币发行商Tether再扩Web3版图!Paolo Ardoino:正开发去中心化搜索引擎Hypersearch
web3.0
稳定币发行商Tether再扩Web3版图!Paolo Ardoino:正开发去中心化搜索引擎Hypersearch

稳定币巨头Tether的动向,向来是加密世界的风向标。这不,它向Web3基础设施的版图扩张,又迈出了关键一步。公司执行长Paolo Ardoino在社交平台X上透露,其工程团队正在全力“烹制”一个新项目——去中心化搜索引擎 “Hypersearch”。这个消息一出,立刻引发了行业的广泛猜想。 采用D

热心网友
04.08
Base链首个原生DeFi借贷协议Seamless Protocol倒闭 将于2026年6月30日下线
web3.0
Base链首个原生DeFi借贷协议Seamless Protocol倒闭 将于2026年6月30日下线

基地位于Coinbase旗下以太坊Layer2网络Base的Seamless Protocol,日前正式宣告了服务的终结。这个曾经吸引了超过20万用户的原生DeFi借贷协议,在运营不到三年后,终究没能跑赢时间。它主打的核心产品是Integrated Leverage Markets(ILMs)——一

热心网友
04.08
PAAL代币如何参与治理?社区投票能决定哪些事项?
web3.0
PAAL代币如何参与治理?社区投票能决定哪些事项?

PAAL代币揭秘:深度解析Web3社区治理的核心钥匙 在去中心化自治组织的浪潮中,谁真正掌握了项目的话语权?PAAL代币提供了一套系统化的答案。它不仅是生态内流转的价值媒介,更是开启链上治理大门的核心凭证。通过持有并质押PAAL代币,用户能够对协议升级、资金分配乃至战略方向等关键事务投出决定性的一票

热心网友
04.08