fastai2 实现SSD

  • https://github.com/search?q=fastai+ssd 有几个值得参考的代码,好好学习。
    • GitHub - Samjoel3101/SSD-Object-Detection: I am working on a SSD Object Detector using fastai and pytorch fastai2实现的SSD,终于找到了code。
    • https://github.com/sidravic/SSD_ObjectDetection_2/tree/master/train 这也是fastai2实现的ssd
  • 很重要的参考:mAP的参考,基于fastai2的结构:GitHub - rbrtwlz/fastai_object_detection: Extension of the fastai library to include object detection.
    • 计划是将这个mAP的计算同SSD结合起来就好了。
  • fastai2的SSD,来自:dhblog - Object Detection from scratch - Single Shot Detector
    • 这个获取data的方式帮助很大

  1.  fastai2和fastai1的bbox都是:x1,y1,x2,y2格式;显示框plt都是x,y,h,w格式
  2. fastai2的bbox范围是[-1,1];显示到224需要变换:
    for i,ax in enumerate(axes.flat): # y~[-1,1]  ([-1,1] + 1)/2~[0,1]
        show_ground_truth(ax, x[i], ((y[0][i] + 1)/2 * 224).cpu(), y[1][i].cpu())
    def draw_rect(ax, b, color='white'):
        patch = ax.add_patch(patches.Rectangle(b[:2], *b[-2:], fill=False, edgecolor=color, lw=2))

" 使用fastai v2 重写ssd by fastai course-v2 2018 part2 pascal_multi.ipynb "

# data pascal_voc2007


import warnings
warnings.filterwarnings('ignore')

import sys
sys.path.insert(0, '/home/zhr/fastai2/fastai_object_detection/fastai_object_detection') # debug源码,而非package

from pathlib import Path
from fastai.vision.all import *
# from zhr_util import get_annotations
from zhr_util import ssd_loss, SSD_Head, SSD_MultiHead, FocalLoss

path = Path('/home/helen/dataset/pascal_2007')

trn_im_names, trn_truths = get_annotations(path/'train.json')
val_im_names, val_truths = get_annotations(path/'valid.json')
# tst_im_names, tst_truths = get_annotations(path/'test.json') 
tot_im_names, tot_truths = [trn_im_names + val_im_names, trn_truths + val_truths]

img_y_dict = dict(zip(tot_im_names, tot_truths))
truth_data_func = lambda o: img_y_dict[o.name]

sz=224       # Image size
bs=64        # Batch size

item_tfms = [Resize(sz, method='squish'),]
batch_tfms = [Rotate(), Flip(), Dihedral()]

getters = [lambda o: path/'train'/o, lambda o: img_y_dict[o][0], lambda o: img_y_dict[o][1]]

pascal = DataBlock(blocks=(ImageBlock, BBoxBlock, BBoxLblBlock),
                   splitter=RandomSplitter(),
                   getters=getters,
                   item_tfms=item_tfms,
                   batch_tfms=batch_tfms,
                   n_inp=1)
dls = pascal.dataloaders(tot_im_names,bs=bs)
# dls.vocab

k = 9
head_reg4 = SSD_MultiHead(k, -3., dls)
body = create_body(resnet34(True))
model = nn.Sequential(body, head_reg4)

ssd_learner = Learner(dls, model, loss_func=ssd_loss)
ssd_learner.fit_one_cycle(3, 1e-3)

import json
import collections
from fastai.vision.all import *

def get_annotations(fname, prefix=None):
    "Open a COCO style json in `fname` and returns the lists of filenames (with maybe `prefix`) and labelled bboxes."
    annot_dict = json.load(open(fname))
    id2images, id2bboxes, id2cats = {}, collections.defaultdict(list), collections.defaultdict(list)
    classes = {}
    for o in annot_dict['categories']:
        classes[o['id']] = o['name']
    for o in annot_dict['annotations']:
        bb = o['bbox']
        id2bboxes[o['image_id']].append([bb[0],bb[1], bb[2]+bb[0], bb[3]+bb[1]])
        id2cats[o['image_id']].append(classes[o['category_id']])
    for o in annot_dict['images']:
        if o['id'] in id2bboxes:
            id2images[o['id']] = ('') + o['file_name']
    ids = list(id2images.keys())
    return [id2images[k] for k in ids], [[id2bboxes[k], id2cats[k]] for k in ids]

" 多类别的标签:fastai v2版本的使用方法 "
# if 0:
    # df = pd.read_csv(path/'train.csv')

    # def get_x(r): return path/'train'/r['fname']
    # def get_y(r): return r['labels'].split(' ')

    # # dblock = DataBlock(blocks=(ImageBlock, MultiCategoryBlock),
    # #                    get_x = get_x, get_y = get_y)
    # # dsets = dblock.datasets(df)

    # def splitter(df):
    #     train = df.index[~df['is_valid']].tolist()
    #     valid = df.index[df['is_valid']].tolist()
    #     return train,valid

    # dblock = DataBlock(blocks=(ImageBlock, MultiCategoryBlock),
    #                 splitter=splitter,
    #                 get_x=get_x, 
    #                 get_y=get_y,
    #                 item_tfms = RandomResizedCrop(224, min_scale=0.35))
    # dls = dblock.dataloaders(df)
        
    # dls.show_batch(max_n=9, figsize=(8, 6))
__all__ = ['get_ssd_model','ssd_resnet34', 'ssd_loss']

# Cell
import torch
from torch import nn
from torch.nn import Module
from torchvision.ops.boxes import batched_nms
from torch.hub import load_state_dict_from_url
from functools import partial
from fastai.vision.all import delegates

from fastai.vision import *
from fastai.callback import *

from fastai.vision import models
from fastai.vision.learner import create_body
from fastai.callback.hook import num_features_model
from fastai.layers import *

import torch.nn.functional as F

# Method used to match the shape of the conv_ssd_layer to the ground truth's shape
def flatten_conv(x,k):
    # Flatten the 4x4 grid to dim16 vectors
    bs,nf,gx,gy = x.size()
    x = x.permute(0,2,3,1).contiguous()
    return x.view(bs,-1,nf//k)

# Standard convolution with stride=2 to halve the size of the image
class OutConv(nn.Module):
    # Output Layers for SSD-Head. Contains oconv1 for Classification and oconv2 for Detection
    def __init__(self, k, nin, bias, dls):
        super().__init__()
        self.k = k
        self.oconv1 = nn.Conv2d(nin, (len(dls.vocab))*k, 3, padding=1)
        self.oconv2 = nn.Conv2d(nin, 4*k, 3, padding=1)
        self.oconv1.bias.data.zero_().add_(bias)
        
    def forward(self, x):
        return [flatten_conv(self.oconv2(x), self.k), # 先box,再label
                flatten_conv(self.oconv1(x), self.k)]
    
# SSD convolution that camptures bounding box and class
class StdConv(nn.Module):
    # Standard Convolutional layers 
    def __init__(self, nin, nout, stride=2, drop=0.1):
        super().__init__()
        self.conv = nn.Conv2d(nin, nout, 3, stride=stride, padding=1)
        self.bn = nn.BatchNorm2d(nout)
        self.drop = nn.Dropout(drop)
        
    def forward(self, x): return self.drop(self.bn(F.relu(self.conv(x))))

device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

class SSD_Head(nn.Module):
    def __init__(self, k, bias, dls):
        super().__init__()
        self.drop = nn.Dropout(0.25)
        self.sconv0 = StdConv(512,256, stride=1)
        self.sconv2 = StdConv(256,256)
        self.out = OutConv(k, 256, bias, dls)
        
    def forward(self, x):
        x = self.drop(F.relu(x))
        x = self.sconv0(x)
        x = self.sconv2(x)
        return self.out(x)



def one_hot_embedding(labels, num_classes):
    return torch.eye(num_classes)[labels].cuda()

# 还是写成GPU格式更为有效,否则
class BCE_Loss(nn.Module):
    def __init__(self, num_classes):
        super().__init__()
        self.num_classes = num_classes

    def forward(self, pred, targ):
        t = one_hot_embedding(targ.squeeze(), self.num_classes)
        t = t[:,1:] # Start from 1 to exclude the Background
        x = pred[:,1:]
        w = self.get_weight(x,t)
        return F.binary_cross_entropy_with_logits(x, t, w.detach(), reduction='sum')/self.num_classes
    
    def get_weight(self,x,t): return None

class FocalLoss(BCE_Loss):
    def get_weight(self,x,t):
        alpha,gamma = 0.25,1
        p = x.sigmoid()
        pt = p*t + (1-p)*(1-t)
        w = alpha*t + (1-alpha)*(1-t)
        return w * (1-pt).pow(gamma)

#convert center/height/width to fastai top left and bottom right coordinates
def cthw2corners(boxes):
    top = (boxes[:,0] - boxes[:,2]/2).view(-1,1)
    left = (boxes[:,1] - boxes[:,3]/2).view(-1,1)
    bot = (boxes[:,0] + boxes[:,2]/2).view(-1,1)
    right = (boxes[:,1] + boxes[:,3]/2).view(-1,1)
    return torch.cat([top,left,bot,right],dim=1)
def hw2corners(ctr, hw): 
    # Function to convert BB format: (centers and dims) -> corners
    return torch.cat([ctr-hw/2, ctr+hw/2], dim=1)
# Filter out all zero-valued bounding boxes
def un_pad(boxes,labels):
    bb_keep = ((boxes[:,2] - boxes[:,0])>0).nonzero()[:,0]
    return boxes[bb_keep],labels[bb_keep]

# Calculate the area of a bounding box
def box_area(boxes):
    return (boxes[:,2] - boxes[:,0]) * (boxes[:,3] - boxes[:,1])

# Calculate the intersection of two given bounding boxes
def intersect(box_a,box_b):
    #make sure box_a and box_b exists, otherwise undefine behavior if you call the func
    top_left = torch.max(box_a[:,None,:2],box_b[None,:,:2])
    bot_right = torch.min(box_a[:,None,2:],box_b[None,:,2:])
    inter = torch.clamp((bot_right - top_left),min=0)
    return inter[:,:,0] * inter[:,:,1]

# Calculate Jaccard (IOU)
def iou(bbox,anchor):
    #bbox is gt_bb, anchor is anchor box, all in fastai style
    if len(bbox.shape) == 1: bbox = bbox[None,...]
    inter = intersect(bbox,anchor)
    union = box_area(bbox).unsqueeze(dim=1) + box_area(anchor).unsqueeze(dim=0) - inter #to broadcast shape to (N,16),where N is number of gt_bb for single image
    return inter / union
# Transform activations to bounding box format
def act_to_bbox(activation,anchor):
    activation = torch.tanh(activation) #force scale to be -1,1
    anchor = anchor.to(device)
    act_center = anchor[:,:2]+ (activation[:,:2]/2 * grid_sizes.float().to(activation.device))
    act_hw = anchor[:,2:] * (activation[:,2:]/2 + 1)
    # return cthw2corners(torch.cat([act_center,act_hw],dim=1))
    return hw2corners(act_center, act_hw)# 速度更快

  # Map to Ground Truth
def map_to_gt(overlaps):
    prior_overlap,prior_idx = overlaps.max(dim=1)
    sec_overlap,sec_idx = overlaps.max(dim=0)
    sec_overlap[prior_idx] = 4.99
    for i,o in enumerate(prior_idx): 
        sec_idx[o] = i
    return sec_overlap,sec_idx

class SSD_MultiHead(nn.Module):
    def __init__(self, k, bias, dls, drop=0.4):
        super().__init__()
        self.drop = nn.Dropout(drop)
        self.sconv0 = StdConv(512,256, stride=1, drop=drop)
        self.sconv1 = StdConv(256,256, drop=drop)
        self.sconv2 = StdConv(256,256, drop=drop)
        self.sconv3 = StdConv(256,256, drop=drop)
        self.out0 = OutConv(k, 256, bias, dls)
        self.out1 = OutConv(k, 256, bias, dls)
        self.out2 = OutConv(k, 256, bias, dls)
        self.out3 = OutConv(k, 256, bias, dls)

    def forward(self, x):
        x = self.drop(F.relu(x))
        x = self.sconv0(x)
        x = self.sconv1(x)
        o1c,o1l = self.out1(x)
        x = self.sconv2(x)
        o2c,o2l = self.out2(x)
        x = self.sconv3(x)
        o3c,o3l = self.out3(x)
        return [torch.cat([o1c,o2c,o3c], dim=1), # box
                torch.cat([o1l,o2l,o3l], dim=1)] # clas






anc_grids = [4, 2, 1]
anc_zooms = [0.75, 1., 1.3]
anc_ratios = [(1., 1.), (1., 0.5), (0.5, 1.)]

anchor_scales = [(anz*i,anz*j) for anz in anc_zooms 
                                    for (i,j) in anc_ratios]
# *** Number of Anchor Scales
k = len(anchor_scales)
# ***************************

import numpy as np
anc_offsets = [2/(o*2) for o in anc_grids] #2 is the h,w in fastai 1.0 (-1,1)
anc_x = np.concatenate([np.repeat(np.linspace(ao-1, 1-ao, ag), ag)
                        for ao,ag in zip(anc_offsets,anc_grids)])
anc_y = np.concatenate([np.tile(np.linspace(ao-1, 1-ao, ag), ag)
                        for ao,ag in zip(anc_offsets,anc_grids)])
anc_ctrs = np.repeat(np.stack([anc_x,anc_y], axis=1), k, axis=0)
anc_sizes = np.concatenate([np.array([[2*o/ag,2*p/ag] 
            for i in range(ag*ag) for o,p in anchor_scales])
                for ag in anc_grids]) #2/grid * scale,2 is the h,w in fastai 1.0
grid_sizes = torch.tensor(np.concatenate([np.array([ 1/ag 
            for i in range(ag*ag) for o,p in anchor_scales])
                for ag in anc_grids])).unsqueeze(1) *2 #again fastai 1.0 h,w is 2
anchors = torch.tensor(np.concatenate([anc_ctrs, anc_sizes], axis=1)).float()
anchor_cnr = cthw2corners(anchors)  
anchors = anchors.to(device)
anchor_cnr = anchor_cnr.to(device)
# 自己的SSD模型
class SSDModel(Module):
    def __init__(self, arch=models.resnet34, k=9, drop=0.4, no_cls=21):
        super().__init__()
        self.k = k
        
        self.body = create_body(arch(True))
        self.backbone = self.body
        self.drop = nn.Dropout(0.2)
        self.std_conv_0 = conv2_std_layer(num_features_model(self.body), 256, drop=drop,stride=1)
        # Dimension-reducing  layers
        self.std_conv_1 = conv2_std_layer(256, 256, drop=drop, stride=2) # 4 by 4 layer
        self.std_conv_2 = conv2_std_layer(256, 256, drop=drop, stride=2) # 2 by 2 layer
        self.std_conv_3 = conv2_std_layer(256, 256, drop=drop, stride=2) # 1 by 1 layer
        # Standard layers
        self.ssd_conv_1 = conv2_ssd_layer(256, k=self.k, no_cls=no_cls)
        self.ssd_conv_2 = conv2_ssd_layer(256, k=self.k, no_cls=no_cls)
        self.ssd_conv_3 = conv2_ssd_layer(256, k=self.k, no_cls=no_cls)

        # self.criterion = FocalLossMy()
        self.device = device
        self.anchors = anchors

    def forward(self, *x):
        imgs, targets = x if len(x)==2 else(x[0], None)
        xb = self.drop(F.relu(self.body(imgs)))
        xb = self.std_conv_0(xb)
        xb = self.std_conv_1(xb)
        bb1, cls1 = self.ssd_conv_1(xb) # 4 x 4
        xb = self.std_conv_2(xb)
        bb2, cls2 = self.ssd_conv_2(xb) # 2 x 2
        xb = self.std_conv_3(xb)     
        bb3, cls3  = self.ssd_conv_3(xb) # 1 x 1
        
        # bboxes = torch.cat([bb1, bb2, bb3], dim=1)
        # clases = torch.cat([cls1, cls2, cls3], dim=1)
        preds = [torch.cat([bb1, bb2, bb3], dim=1), 
                torch.cat([cls1, cls2, cls3], dim=1)]
        return preds
        # if targets is not None: # 训练过程
        #     cls_loss, reg_loss = self.criterion(preds, targets, self.anchors)
        #     return {"cls_loss": cls_loss, "reg_loss":reg_loss}
        # else:#验证过程
        #     predsOut = self.postprocess(imgs, self.anchors, preds)
        #     return predsOut
    
    def postprocess(self, x, anchors, preds):
        return None
loss_f = FocalLoss(21)

def ssd_1_loss(b_c,b_bb,bbox,clas,print_it=False):
    bbox,clas = un_pad(bbox,clas)
    a_ic = act_to_bbox(b_bb, anchors) # 之前的代码是有问题的,应该先转换激活元
    overlaps = iou(bbox.data, anchor_cnr.data)
    gt_overlap,gt_idx = map_to_gt(overlaps) # 找到真实的anchor
    gt_clas = clas[gt_idx]
    pos = gt_overlap > 0.4
    pos_idx = torch.nonzero(pos)[:,0]
    gt_clas[~pos] = 0
    gt_bbox = bbox[gt_idx]
    # loc_loss = ((a_ic[pos_idx] - gt_bbox[pos_idx]).abs()).mean()
    loc_loss = ((TensorBase(a_ic[TensorBase(pos_idx)]) - TensorBase(gt_bbox[TensorBase(pos_idx)])).abs()).mean()
    clas_loss  = loss_f(b_c, gt_clas)
    return loc_loss, clas_loss


def ssd_loss(pred,*targ,print_it=False):
    lcs,lls = 0.,0.
    for b_bb,b_c,bbox,clas in zip(*pred,*targ):
        loc_loss,clas_loss = ssd_1_loss(b_c,b_bb,bbox,clas,print_it)
        lls += loc_loss
        lcs += clas_loss
    if print_it: print(f'loc: {lls.data}, clas: {lcs.data}')
    # bce_loss就注释掉
#     if print_it: print(f'loc: {lls.data[0]}, clas: {lcs.data[0]}')
    return lls+lcs
 
  
    
@delegates(SSDModel)
def get_ssd_model(arch_str, num_classes, pretrained=True, pretrained_backbone=True,
                   trainable_layers=5, **kwargs):
    model = SSDModel(arch=arch_str, no_cls=num_classes)
    return model


ssd_resnet34 = partial(get_ssd_model, arch_str=models.resnet34)





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

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

相关文章

【NLP实战】基于Bert和双向LSTM的情感分类【上篇】

文章目录 前言简介数据获取与提取数据清洗读取数据,查看数据清洗训练集观察数据分布去除空数据去除重复数据关于去除停用词关于特殊符号储存清洗后的数据集 清洗测试集观察数据分布去除空数据去除重复数据(并储存) 清洗验证集观察数据分布去除空行去除重复数据(并储…

16.基于主从博弈理论的共享储能与综合能源微网优化运行研究

说明书 MATLAB代码:基于主从博弈理论的共享储能与综合能源微网优化运行研究 关键词:主从博弈 共享储能 综合能源微网 优化调度 参考文档:《基于主从博弈理论的共享储能与综合能源微网优化运行研究》完全复现 仿真平台:MATLAB …

图解项目管理必备十大管理模型

请点击↑关注、收藏,本博客免费为你获取精彩知识分享!有惊喜哟!! 心智模型 心智模型是根深蒂固存在于人们心中,影响人们如何理解这个世界(包括我们自己、他人、组织和整个世界),以及…

pytest - Getting Start

前言 项目开发中有很多的功能,通常开发人员需要对自己编写的代码进行自测,除了借助postman等工具进行测试外,还需要编写单元测试对开发的代码进行测试,通过单元测试来判断代码是否能够实现需求,本文介绍的pytest模块是…

Android APK 反编译后重新打包并签名

APKTool: Apktool 是一个逆向android非常有用的工具,可以用来反编译apk文件,并且能在修改部分资源文件后,重新打包成一个新的apk。 下载连接:http://ibotpeaches.github.io/Apktool/install/ 下载之后文件夹非常清爽&…

ChatGPT会颠覆SEO内容创作吗

近几年 AI 的发展日新月异。除了搜索算法本身大规模应用人工智能,我也一直关注着 AI 用于写作的进展。 上篇关于 Google 有用内容更新的帖子还在说,高质量内容创作是 SEO 最难的事之一,对某些网站来说,如果能有工具帮助&#xff…

Mysql 日志

目录 0 课程视频 1 错误日志 -> 默认开启 1.1 查看变量 show variables like %log_error%; 1.2 文件位置 /var/log -> mysqld.log 1.3 指令语法 2 二进制日志 -> 修改数据和数据库结构的日志 2.1 记录原则 2.1.1 记录 数据库创建语句 和 增删改查 2.1.2 不记…

JdbcTemplate常用语句代码示例

目录 JdbcTemplate 需求 官方文档 JdbcTemplate-基本介绍 JdbcTemplate 使用实例 需求说明 创建数据库 spring 和表 monster 创建配置文件 src/jdbc.properties 创建配置文件 src/JdbcTemplate_ioc.xml 创建类JdbcTemplateTest测试是否可以正确得到数据源 配置 J…

智能算法系列之基于粒子群优化的模拟退火算法

文章目录 前言1. 算法结合思路2. 问题场景2.1 Sphere2.2 Himmelblau2.3 Ackley2.4 函数可视化 3. 算法实现代码仓库:IALib[GitHub] 前言 本篇是智能算法(Python复现)专栏的第四篇文章,主要介绍粒子群优化算法与模拟退火算法的结合,以弥补各自…

《基于EPNCC的脉搏信号特征识别与分类研究》阅读笔记

目录 一、论文摘要 二、论文十问 三、论文亮点与不足之处 四、与其他研究的比较 五、实际应用与影响 六、个人思考与启示 参考文献 一、论文摘要 为了快速获取脉搏信号的完整表征信息并验证脉搏信号在相关疾病临床诊断中的敏感性和有效性。在本文中,提出了一…

Ubantu docker学习笔记(八)私有仓库

文章目录 一、建立HTTPS链接1.在仓库服务器上获取TLS证书1.1 生成证书颁发机构证书1.2 生成服务器证书1.3 利用证书运行仓库容器 2.让私有仓库支持HTTPS3.客户端端配置 二、基本身份验证三、对外隐藏仓库服务器3.1 在服务器端3.2 在客户端进行 四、仓库可视化 在前面的学习中&a…

ChatGPT被淘汰了?Auto-GPT到底有多强

大家好,我是可夫小子,关注AIGC、读书和自媒体。解锁更多ChatGPT、AI绘画玩法。 说Auto-GPT淘汰了ChatGPT了,显然是营销文案里面的标题党。毕竟它还是基于ChatGPT的API,某种意义只是基于ChatGPT能力的应用。但最近,Auto…

Nautilus Chain Layer 3 圆桌会议圆满举办,超4.8K用户观看

在4月21日,Nautilus Chain举办了以“Layer 3区块链的意义和发展以及Crypto的演变”为主题的线上圆桌会议,我们邀请了众多行业嘉宾包括GitcoinDAO社区管理者Bob jiang、Whalers Community发起者崔棉大师、Chatpuppy联合创始人 古千峰、Whalers Community核…

机器学习与深度学习——通过决策树算法分类鸢尾花数据集iris求出错误率画出决策树并进行可视化

什么是决策树? 决策树是一种常用的机器学习算法,它可以对数据集进行分类或回归分析。决策树的结构类似于一棵树,由节点和边组成。每个节点代表一个特征或属性,每个边代表一个判断或决策。从根节点开始,根据特征的不同…

vue3的props和defineProps

文章目录 1. Props 声明1.1 props用字符串数组来声明Blog.vueBlogPost.vue 1.2 props使用对象来声明Blog.vueBlogPost.vue 2. 传递 prop 的细节2.1 Prop 名字格式2.1 静态Prop & 动态 Prop静态prop动态prop示例Blog.vueBlogPost.vue 2.3 传递不同的值类型NumberBooleanArra…

基于YOLOv4的目标检测系统(附MATLAB代码+GUI实现)

摘要:本文介绍了一种MATLAB实现的目标检测系统代码,采用 YOLOv4 检测网络作为核心模型,用于训练和检测各种任务下的目标,并在GUI界面中对各种目标检测结果可视化。文章详细介绍了YOLOv4的实现过程,包括算法原理、MATLA…

C++知识点 -- 异常

C知识点 – 异常 文章目录 C知识点 -- 异常一、异常概念二、异常的使用1.异常的抛出和捕获2.异常的重新抛出3.异常安全4.异常规范 三、自定义异常体系四、C标准库的异常体系五、C异常的优缺点 一、异常概念 当一个函数发现自己无法处理错误时,就可以抛出异常&#…

14-3-进程间通信-消息队列

前面提到的管道pipe和fifo是半双工的,在某些场景不能发挥作用; 接下来描述的是消息队列(一种全双工的通信方式); 比如消息队列可以实现两个进程互发消息(不像管道,只能1个进程发消息&#xff…

kali: kali工具-Ettercap

kali工具-Ettercap ettercap工具: 用来进行arp欺骗,可以进行ARP poisoning(arp投毒),除此之外还可以其他功能: ettercap工具的arp投毒可以截取web服务器、FTP服务器账号密码等信息,简略后打印出…

前端学习之使用JavaScript

前情回顾:网页布局 JavaScript 简介 avaScript诞生于1995年,它的出现主要是用于处理网页中的前端验证。所谓的前端验证,就是指检查用户输入的内容是否符合一定的规则。比如:用户名的长度,密码的长度,邮箱的…