如何实现sam(Segment Anything Model)|fastsam模型

news2025/1/19 17:10:35

sam是2023年提出的一个在图像分割领域的大模型,其具备了对任意现实数据的分割能力,其论文的介绍可以参考 https://hpg123.blog.csdn.net/article/details/131137939,sam的亮点在于提出一种工作模式,同时将多形式的prompt集成到了语义分割中,其网络结构并没有特殊设计。拓展sam所发展的mobile-sam只是对sam项目中图像编码器的优化,并未在技术提出显著的亮点。故而对sam工作模式进行深入分析,主要深入分析sam的模型设计范式、数据标签范式、fast-sam模型训练范式。
sam的试用地址为:https://segment-anything.com/demo

本博文主要参考资料来自:https://hpg123.blog.csdn.net/article/details/131137939、https://hpg123.blog.csdn.net/article/details/131234476、https://hpg123.blog.csdn.net/article/details/131194434

通过本博文的查阅与分析,实现fastsam是较为简便的,且fastsam的性能可以随着全景实例分割模型的发展而进一步提升,同时也说明了fastsam中prompt的实现。而在sam中,各种实现较为生涩难懂,主要说明sam的模型结构,基本原理,数据生成范式。sam的亮点在于基于少量的语义分割标签,迭代出了一个1.1B 标签超大型数据集,其不断扩展标注数据量的思想是值得学习的;而在fastsam中则是对SAT重新定义得出SAT,基于对全景实例分割模型的后处理实现了类似sam的性能。从sam到fastsam所透露的是数据伪标签拓展的重要性,没有sam发布的数据集,fastsam是无法达到预期性能的。

1、模型设计范式

1.1 sam范式分析

根据论文给出的图表来看,sam的输入包含2部分,原始图片与Prompt(mask、point、boxes、text其中text是基于clip进行编码直接输入)。
在这里插入图片描述
从sam发布的代码来看,其prompt仅包含mask、point、boxes,且三者处于等价地位(同时其官网也未提供基于text的解码)。由代码所得出的sam模型体系如下所示,具体为3个步骤:1.图像编码、2.promp编码、3. 根据promp编码对图像进行解码操作。在mobilenet中完全延用了sam的范式,只是对image_encoder进行了一个蒸馏,从而实现了性能的提升 ; 在fast-sam中只是正式提出将SAT分解为2阶段,第一阶段为对输入图像的全景实例分割,第二阶段为根据提示输入对全景实例分割结果进行稀疏化选择
在这里插入图片描述

在mobilesam论文给出的sam结构图中,可以看出sam模型的主要参数在图像编码器中,而在prompt部分较少
在这里插入图片描述

1.2 图像编码器简介

在sam中使用ImageEncoderViT作为图像编码器,其性能饱和慢随着数据增长,精度可持续增长,用到了1100万的训练图片。原始ViT也是在 ImageNet、ImageNet-21k和JFT- 300M进行训练,并表明JFT-300M效果更好。sam中的Vit与原始模型有细微差异,其输入shape为3x1024x1024,输出的feature map为256x64x64。 这里可以透露出sam最多分割256个mask,这样子设计或许与mask图像uint8的表示范围有关

补偿知识:
1、mobile-sam使用解耦蒸馏方法(只对图像编码器进行蒸馏),使backbone与原始的解码器相适应,整个训练在一个GPU上不到一天,将编码器参数减少100倍,总参数减少60倍。
2、mobile-sam蒸馏后的图像编码器运行为8 ms,mask解码器运行为2 ms,总体运行时间为10ms,比FastSAM快4倍。
3、mobile-sam其基于conv和transformer设计了轻量化的图像编码器;同时,为了加快训练,保存了教师模型预测的特征编码,减少了知识蒸馏中教师模型forward的时间。

1.3 PromptEncoder简介

PromptEncoder属于轻量化的结构,用于对输入模型的points、boxes和masks信息进行编码,将其统一为空间特征编码的格式。其对points、boxes和masks编码时允许有部分值空缺(空缺使用默认值),其将points和boxes组装为sparse_embeddings将mask组装为dense_embeddings 其对mask的采样由多个attention层实现,具体可见mask_downscaling函数。
在这里插入图片描述
PromptEncoder将points、boxes编码为sparse_embeddings拼接在一起,将mask编码为dense_embeddings;同时允许任意prompt输入为空

1.4 MaskDecoder说明

MaskDecoder是sam的核心部分,用于根据输入给出预期输出。其核心代码为predict_masks函数,输入包含
image_embeddings、image_pe、sparse_prompt_embeddings、dense_prompt_embeddings,

在这个过程中代表mask的dense_prompt_embeddings与image_embeddings直接作用,对应的输出经过TwoWayTransformer后变为了mask_tokens_out

代表box与point的sparse_prompt_embeddings与iou_token直接作用,对应的输出经过TwoWayTransformer后变为了iou_token_out .

最后由IOU预测模块,输出每个mask的iou

MaskDecoder的本质就是根据图像编码与prompt编码输出mask与iou得分(基于输出的mask、iou得分,或许可以与标签mask、标签iou得分进行训练),至于为什么计较这么复杂,博主尚未理清楚。或许参考fast-sam的实现可以理通,但从mobile的实现思路来看是可以规避这个问题(直接使用sam的MaskDecoder)。
在这里插入图片描述

2、数据标签范式

2.1 Segment Anything Dataset

sam提出了数据集Segment Anything Dataset,其中包含由1100万多样化、高分辨率、许可和隐私保护图像(平均像素3300×4950),并包含1.1B高质量分割掩码(其中99.1%是完全自动生成的;并抽取了500个图【50k个mask】进行了人工验证,94%的图像对IoU大于90%(97%的对的IoU大于75%))。

sad的数据分布特性如下所示,大部分数据的mask数量处于50~200个。
在这里插入图片描述

2.2 SAD数据引擎

Segment Anything Data Engine分为三个阶段: (1)模型辅助手动标注阶段,(2)包含自动预测掩码和模型辅助标注的半自动阶段,(3)全自动阶段,在此阶段中,我们的模型生成掩码而无需标注器输入;最终生成Segment Anything Dataset。

辅助手动阶段:类似于经典的交互式分割,通过点击前景/背景对象点来标记掩码,要求按突出程度的顺序标记物体,自动生成mask。mask可以使用像素精确的“笔刷”和“橡皮擦”工具来改进。

同时,SAM使用常见的公共分割数据集进行训练。在进行足够的数据标注后,只使用新标注的掩码进行重新训练。随着更多的掩模被收集到,图像编码器从ViT-B缩放到ViT-H,同时训练细节随着模型调整不断优化。总共对模型进行了6次再训练。随着模型的改进,每个mask的平均标注时间从34秒减少到14秒; 每幅图像的平均掩模数量从20个增加到44个; 从12万张图像中收集了430万个mask

该阶段,要求已经具备类似sam的模型能根据prompt进行初级的语义分割能力,只是类sam模型预测的结果有待人工优化。

半自动阶段: 在这个阶段,目标是增加mask的多样性,以提高模型分割任何东西的能力。为了将标注器集中在不太突出的对象上,首先自动检测到较为突出的mask。然后,我们提供了预先填充了这些掩码的图像的标注器,并要求它们标注任何其他未标注的对象。

为了检测突出的掩模,将第一阶段所有的mask都整理成目标检测标签,类别为“object”,训练了一个边界框检测器[84]。然后要求检测器自动检测出突出的mask的boxes,然后根据boxes重新进行mask生成在这一阶段,在18万张图像中收集了额外5.9M的mask(总共有10.2M的mask)

与第一阶段一样,定期使用新收集的数据重新训练模型(5次),该操作使mask数量从44个增加到72个(包括自动mask)

该阶段,主要目的就是泛化检测模型对突出物体的检测能力,找到未标注区域、泛化sam对未标注区域的标签生成能力。先基于检测模型找到待标注的显著区域,然后使用模型生成伪标签,不断扩展数据的mask数量,同时相比于第一阶段,补充了6万个数据

全自动阶段:
该阶段有两个主要的增强,1:mask足够充分,2、设计了模糊感知模型,它允许在模糊情况下预测出有效mask。

该阶段已经使用了sam的自动分割功能,用一个32×32规则点网格提示模型,为每个点预测一组可能对应于有效对象的掩模上一个阶段使用检测模型进行标注。如果点位于一个部分或子部分上,模糊感知模型将返回该子部分、部件和整个对象。模型的IoU预测模块用于选择自信的掩模;此外,只识别和选择稳定的mask。最后,在选择了自信和稳定的掩模后,应用非最大抑制(NMS)来过滤多余mask。

trick1:为了进一步提高较小掩模的质量,处理了多个重叠的放大图像crop。有关此阶段的详细信息

对数据集中的所有11M幅图像应用了全自动掩模生成,总共产生了1.1B个高质量的掩模。

3、fast-sam模型训练范式

sam只是对Segment Anything进行了一个初步的定义,描述了其是如何基于0.9%的人工数据标签生成100%的数据,并未讲述其对sad数据集的再训练。
fast-sam项目地址为:https://github.com/CASIA-IVA-Lab/FastSAM
fast-sam demo地址为:https://huggingface.co/spaces/An-619/FastSAM

3.1 Segment Anything Task定义

FastSAM定义Segment Anything Task(SAT)为根据提示进行语义分割任务,提示指:前景|背景点、bounding boxes、mask、text;

FastSAM将SAT分解为2阶段,第一阶段为对输入图像的全景实例分割,第二阶段为根据提示输入对全景实例分割结果进行稀疏化选择。其能如此实现,主要是sad完成了数据mask从稀疏到全景的标注

3.2 fast-sam实现

fast-sam由yolov8-seg(全景实例分割)+Prompt-guided-Selection模块组成,从其结构图中可以看到两个模块是可以孤立训练的。

在这里插入图片描述
这里以ultralytics中对fast-sam的实现为基准,可以看到FastSAM就是对yolov8模型的继承,这里的FastSAM只是一个通用的全景实例分割模型。

# Ultralytics YOLO 🚀, AGPL-3.0 license

from pathlib import Path
from ultralytics.engine.model import Model
from .predict import FastSAMPredictor
from .val import FastSAMValidator
class FastSAM(Model):
    """
    FastSAM model interface.
    Example:
        ```python
        from ultralytics import FastSAM
        model = FastSAM('last.pt')
        results = model.predict('ultralytics/assets/bus.jpg')
        ```
    """

    def __init__(self, model='FastSAM-x.pt'):
        """Call the __init__ method of the parent class (YOLO) with the updated default model."""
        if str(model) == 'FastSAM.pt':
            model = 'FastSAM-x.pt'
        assert Path(model).suffix not in ('.yaml', '.yml'), 'FastSAM models only support pre-trained models.'
        super().__init__(model=model, task='segment')

    @property
    def task_map(self):
        """Returns a dictionary mapping segment task to corresponding predictor and validator classes."""
        return {'segment': {'predictor': FastSAMPredictor, 'validator': FastSAMValidator}}

其使用代码如下所示,先由FastSAM分割出全景mask,再由FastSAMPrompt根据输入提示筛选mask


from fastsam import FastSAM, FastSAMPrompt
import torch 

model = FastSAM('FastSAM.pt')
IMAGE_PATH = './images/dogs.jpg'
DEVICE = torch.device(
    "cuda"
    if torch.cuda.is_available()
    else "mps"
    if torch.backends.mps.is_available()
    else "cpu"
)
everything_results = model(
    IMAGE_PATH,
    device=DEVICE,
    retina_masks=True,
    imgsz=1024,
    conf=0.4,
    iou=0.9,
)
prompt_process = FastSAMPrompt(IMAGE_PATH, everything_results, device=DEVICE)

# # everything prompt
ann = prompt_process.everything_prompt()  #这里就是everything_results

# # bbox prompt
# # bbox default shape [0,0,0,0] -> [x1,y1,x2,y2]
# bboxes default shape [[0,0,0,0]] -> [[x1,y1,x2,y2]]
# ann = prompt_process.box_prompt(bbox=[200, 200, 300, 300])
# ann = prompt_process.box_prompt(bboxes=[[200, 200, 300, 300], [500, 500, 600, 600]])

# # text prompt
# ann = prompt_process.text_prompt(text='a photo of a dog')

# # point prompt
# # points default [[0,0]] [[x1,y1],[x2,y2]]
# # point_label default [0] [1,0] 0:background, 1:foreground
# ann = prompt_process.point_prompt(points=[[620, 360]], pointlabel=[1])

# point prompt
# points default [[0,0]] [[x1,y1],[x2,y2]]
# point_label default [0] [1,0] 0:background, 1:foreground
ann = prompt_process.point_prompt(points=[[620, 360]], pointlabel=[1])

prompt_process.plot(
    annotations=ann,
    output='./output/',
    mask_random_color=True,
    better_quality=True,
    retina=False,
    withContours=True,
)

3.3 FastSAMPrompt

FastSAMPrompt是fastsam的核心,其用于根据prompt从现有全景分割结果中遴选出目标mask。其本身不带任何可训练参数,从代码上看其仅支持point、box、text形式的prompt不支持mask嵌入

bbox prompt

实现代码如下所示,代码行数较多,以博主的理解就是根据bbox 生成mask,然后计算与全景分割所有mask的iou,然后找出iou最大的进行输出。因此,这里输入bbox ,只会输出一个mask。


    def box_prompt(self, bbox):
        """Modifies the bounding box properties and calculates IoU between masks and bounding box."""
        if self.results[0].masks is not None:
            assert (bbox[2] != 0 and bbox[3] != 0)
            if os.path.isdir(self.source):
                raise ValueError(f"'{self.source}' is a directory, not a valid source for this function.")
            masks = self.results[0].masks.data
            target_height, target_width = self.results[0].orig_shape
            h = masks.shape[1]
            w = masks.shape[2]
            if h != target_height or w != target_width:
                bbox = [
                    int(bbox[0] * w / target_width),
                    int(bbox[1] * h / target_height),
                    int(bbox[2] * w / target_width),
                    int(bbox[3] * h / target_height), ]
            bbox[0] = max(round(bbox[0]), 0)
            bbox[1] = max(round(bbox[1]), 0)
            bbox[2] = min(round(bbox[2]), w)
            bbox[3] = min(round(bbox[3]), h)

            # IoUs = torch.zeros(len(masks), dtype=torch.float32)
            bbox_area = (bbox[3] - bbox[1]) * (bbox[2] - bbox[0])

            masks_area = torch.sum(masks[:, bbox[1]:bbox[3], bbox[0]:bbox[2]], dim=(1, 2))
            orig_masks_area = torch.sum(masks, dim=(1, 2))

            union = bbox_area + orig_masks_area - masks_area
            iou = masks_area / union
            max_iou_index = torch.argmax(iou)

            self.results[0].masks.data = torch.tensor(np.array([masks[max_iou_index].cpu().numpy()]))
        return self.results

point prompt
point 的实现代码如下所示,其本质就是遍历所有全景分割mask,将point正例所击中的mask添加到onemask 中,将point负例所击中的mask从onemask 中删除,然后返回onemask

    def point_prompt(self, points, pointlabel):  # numpy
        """Adjusts points on detected masks based on user input and returns the modified results."""
        if self.results[0].masks is not None:
            if os.path.isdir(self.source):
                raise ValueError(f"'{self.source}' is a directory, not a valid source for this function.")
            masks = self._format_results(self.results[0], 0)
            target_height, target_width = self.results[0].orig_shape
            h = masks[0]['segmentation'].shape[0]
            w = masks[0]['segmentation'].shape[1]
            if h != target_height or w != target_width:
                points = [[int(point[0] * w / target_width), int(point[1] * h / target_height)] for point in points]
            onemask = np.zeros((h, w))
            for annotation in masks:
                mask = annotation['segmentation'] if isinstance(annotation, dict) else annotation
                for i, point in enumerate(points):
                    if mask[point[1], point[0]] == 1 and pointlabel[i] == 1:
                        onemask += mask
                    if mask[point[1], point[0]] == 1 and pointlabel[i] == 0:
                        onemask -= mask
            onemask = onemask >= 1
            self.results[0].masks.data = torch.tensor(np.array([onemask]))
        return self.results

text prompt
相关代码如下所示,关键函数为retrieve。其先使用_crop_image将全景实例分割中mask对应的图片全部crop出来,然后使用clip分别计算出mask crop与tokenized_text 的余弦相似度,最后找出余弦相似度大于阈值的mask即可。

    def text_prompt(self, text):
        """Processes a text prompt, applies it to existing results and returns the updated results."""
        if self.results[0].masks is not None:
            format_results = self._format_results(self.results[0], 0)
            cropped_boxes, cropped_images, not_crop, filter_id, annotations = self._crop_image(format_results)
            clip_model, preprocess = self.clip.load('ViT-B/32', device=self.device)
            scores = self.retrieve(clip_model, preprocess, cropped_boxes, text, device=self.device)
            max_idx = scores.argsort()
            max_idx = max_idx[-1]
            max_idx += sum(np.array(filter_id) <= int(max_idx))
            self.results[0].masks.data = torch.tensor(np.array([annotations[max_idx]['segmentation']]))
        return self.results
        
    @torch.no_grad()
    def retrieve(self, model, preprocess, elements, search_text: str, device) -> int:
        """Processes images and text with a model, calculates similarity, and returns softmax score."""
        preprocessed_images = [preprocess(image).to(device) for image in elements]
        tokenized_text = self.clip.tokenize([search_text]).to(device)
        stacked_images = torch.stack(preprocessed_images)
        image_features = model.encode_image(stacked_images)
        text_features = model.encode_text(tokenized_text)
        image_features /= image_features.norm(dim=-1, keepdim=True) #先除模
        text_features /= text_features.norm(dim=-1, keepdim=True) #先除模
        probs = 100.0 * image_features @ text_features.T #再做乘法,实现余弦相似度计算
        return probs[:, 0].softmax(dim=0)
        
    def _crop_image(self, format_results):
        """Crops an image based on provided annotation format and returns cropped images and related data."""
        if os.path.isdir(self.source):
            raise ValueError(f"'{self.source}' is a directory, not a valid source for this function.")
        image = Image.fromarray(cv2.cvtColor(self.results[0].orig_img, cv2.COLOR_BGR2RGB))
        ori_w, ori_h = image.size
        annotations = format_results
        mask_h, mask_w = annotations[0]['segmentation'].shape
        if ori_w != mask_w or ori_h != mask_h:
            image = image.resize((mask_w, mask_h))
        cropped_boxes = []
        cropped_images = []
        not_crop = []
        filter_id = []
        for _, mask in enumerate(annotations):
            if np.sum(mask['segmentation']) <= 100:
                filter_id.append(_)
                continue
            bbox = self._get_bbox_from_mask(mask['segmentation'])  # mask 的 bbox
            cropped_boxes.append(self._segment_image(image, bbox))  # 保存裁剪的图片
            cropped_images.append(bbox)  # 保存裁剪的图片的bbox

        return cropped_boxes, cropped_images, not_crop, filter_id, annotations

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

清华把大模型用于城市规划,回龙观和大红门地区成研究对象

引言&#xff1a;参与式城市规划的新篇章 随着城市化的不断推进&#xff0c;传统的城市规划方法面临着越来越多的挑战。这些方法往往需要大量的时间和人力&#xff0c;且严重依赖于经验丰富的城市规划师。为了应对这些挑战&#xff0c;参与式城市规划应运而生&#xff0c;它强…

短剧在线搜索源码(全网首发)

一个非常哇塞的在线短剧搜索页面&#xff0c;接口已经对接好了&#xff0c;上传源码到服务器解压就能直接用&#xff0c;有能力的可以自己改接口自己写自己的接口 接口文档地址&#xff1a;doc.djcat.sbs 源码下载地址&#xff1a;https://pan.xunlei.com/s/VNstN8C6N3VK1a1k…

《OWASP TOP10漏洞》

0x01 弱口令 产生原因 与个人习惯和安全意识相关&#xff0c;为了避免忘记密码&#xff0c;使用一个非常容易记住 的密码&#xff0c;或者是直接采用系统的默认密码等。 危害 通过弱口令&#xff0c;攻击者可以进入后台修改资料&#xff0c;进入金融系统盗取钱财&#xff0…

【算法与数据结构】队列的实现详解

文章目录 &#x1f4dd;队列的概念及结构&#x1f320; 队列的顺序实现&#x1f309;初始化&#x1f320;入队&#x1f309;出队&#x1f320;获取队列首元素&#x1f309;获取队列尾部元素&#x1f320;获取队列中有效元素个数&#x1f309; 队列是否为空&#x1f320;查看队列…

二分查找的理解及应用场景。

一、是什么 在计算机科学中&#xff0c;二分查找算法&#xff0c;也称折半搜索算法&#xff0c;是一种在有序数组中查找某一特定元素的搜索算法 想要应用二分查找法&#xff0c;则这一堆数应有如下特性&#xff1a; 存储在数组中有序排序 搜索过程从数组的中间元素开始&…

【典】dp背包问题(树求方案)

回顾在acw上做过的题 有依赖的背包问题 这一题是与树相关的dp问题&#xff0c;根据父节点与子节点的相连关系&#xff0c;我们用dfs来处理根节点与子树的迭代更新&#xff0c;把每一颗最小单位子树看成一个物品&#xff0c;然后就有点像多重背包&#xff08;因为有体积限制&…

云计算 3月12号 (PEX)

什么是PXE&#xff1f; PXE&#xff0c;全名Pre-boot Execution Environment&#xff0c;预启动执行环境&#xff1b; 通过网络接口启动计算机&#xff0c;不依赖本地存储设备&#xff08;如硬盘&#xff09;或本地已安装的操作系统&#xff1b; 由Intel和Systemsoft公司于199…

【vue在主页中点击主页面如何弹出一个指定某个页面的窗口】

【vue在主页中点击主页面跳转到某个页面的操作完整过程】 1.首先在主页面中加入一个卡槽用于展示弹出的窗口 代码如下&#xff1a; <el-dialog :visible.sync"dialogVisible1" :close-on-click-modal"false" :title"title" class"dial…

关于tcp协议

目录 前言&#xff1a; 一、TCP协议的基本概念&#xff1a; 二、TCP协议的主要特点&#xff1a; 2.1面向连接&#xff1a; 2.2可靠传输&#xff1a; 2.3基于字节流&#xff1a; 三、TCP连接的建立与终止&#xff1a; 3.1连接建立&#xff1a; 3.1.1SYN&#xff1a; 3…

资产管理系统建设方案参考

1系统概述 软件开发全套文档下载、源码下载&#xff1a;软件项目开发全套文档下载_软件开发文档下载-CSDN博客 1.1需求描述 1. 实现公司内部固定资产管理全生命周期管理&#xff0c;包括资产采购、资产入库、资产领用、资产借用、资产归还、资产报废、资产维修、资产调拨等全…

RC522刷卡电路设计及程序

一、RC522刷卡电路组成 基于RC522的刷卡电路如上图所示。该电路组成主要分为三部分&#xff1a; Receiving Circuit&#xff1a;接收电路&#xff0c;接收卡发送的数据。 Filtering Impedence-Transtorm circuit:滤波和阻抗变换电路&#xff0c;抑制高次谐波并优化到读卡器天线…

Python使用lxml解析XML格式化数据

Python使用lxml解析XML格式化数据 1. 效果图2. 源代码参考 方法一&#xff1a;无脑读取文件&#xff0c;遇到有关键词的行再去解析获取值 方法二&#xff1a;利用lxml等库&#xff0c;解析格式化数据&#xff0c;批量获取标签及其值 这篇博客介绍第2种办法&#xff0c;以菜鸟教…

【AI大模型应用开发】【LangChain系列】9. 实用技巧:大模型的流式输出在 OpenAI 和 LangChain 中的使用

大家好&#xff0c;我是同学小张&#xff0c;日常分享AI知识和实战案例欢迎 点赞 关注 &#x1f44f;&#xff0c;持续学习&#xff0c;持续干货输出。v: jasper_8017 一起交流&#x1f4ac;&#xff0c;一起进步&#x1f4aa;。微信公众号也可搜【同学小张】 &#x1f64f; 本…

Linux环境(Ubuntu)上搭建MQTT服务器(EMQX )

目录 概述 1 认识EMQX 1.1 EMQX 简介 1.2 EMQX 版本类型 2 Ubuntu搭建EMQX 平台 2.1 下载和安装 2.1.1 下载 2.1.2 安装 2.2 查看运行端口 3 运行Dashboard 管理控制台 3.1 查看Ubuntu上的防火墙 3.2 运行Dashboard 管理控制台 概述 本文主要介绍EMQX 的一些内容&a…

Vulnhub - DevGuru

希望和各位大佬一起学习&#xff0c;如果文章内容有错请多多指正&#xff0c;谢谢&#xff01; 个人博客链接&#xff1a;CH4SER的个人BLOG – Welcome To Ch4sers Blog DevGuru 靶机下载地址&#xff1a;DevGuru: 1 ~ VulnHub 目录 0x01 信息收集 0x02 Web漏洞利用 - W…

GPT-4.5 Turbo意外曝光,最快明天发布?OpenAI终于要放大招了!

大家好&#xff0c;我是木易&#xff0c;一个持续关注AI领域的互联网技术产品经理&#xff0c;国内Top2本科&#xff0c;美国Top10 CS研究生&#xff0c;MBA。我坚信AI是普通人变强的“外挂”&#xff0c;所以创建了“AI信息Gap”这个公众号&#xff0c;专注于分享AI全维度知识…

什么是信创?什么是信创测评?

信创&#xff0c;全称为信息技术应用创新&#xff0c;我的理解&#xff0c;其核心是知识产权与供应链的自主可控与可持续发展。 我国在经历了无数风雨后&#xff0c;已经浴火重生&#xff0c;国家实力日益强大&#xff0c;人民生活水平也不断提高。然而&#xff0c;我们必须清…

彩虹知识付费模板MangoA全开源包含秒杀/抽奖/社群/推送等功能

二次开发增加以下功能每日秒杀每日签到官方社群多级分销在线抽奖项目投稿 每日秒杀 每日签到 官方社群 多级分销 在线抽奖 项目投稿 下载地址&#xff1a;https://pan.xunlei.com/s/VNstMfOecGliiqew7UIorsOnA1?pwdhywi#

2024年云仓酒庄:店中店增项新模式,开启葡萄酒文化新篇章

2024云仓酒庄&#xff1a;店中店增项新模式&#xff0c;开启葡萄酒文化新篇章 在葡萄酒行业蓬勃发展的今天&#xff0c;云仓酒庄以其独特的经营模式和创新思维&#xff0c;在市场中脱颖而出。2024年&#xff0c;云仓酒庄继续深化其战略布局&#xff0c;不仅在多地开设酒庄实体…

微信小程序开发系列(三十二)·如何通过小程序的API实现页面的上拉加载(onReachBottom事件)和下拉刷新(onPullDownRefresh事件)

目录 1. 上拉加载 2. 下拉刷新 1. 上拉加载 上拉加载是小程序中常见的一种加载方式&#xff0c;当用户滑动页面到底部时&#xff0c;会自动加载更多的内容&#xff0c;以便用户继续浏览小程序中实现上拉加载的方式&#xff1a; ① 在app.json或者page.json中配置距离页面…