鼠标点击下载     项目源代码免费下载地址

<计算机视觉一> 使用标定工具标定自己的目标检测

<计算机视觉二> labelme标定的数据转换成yolo训练格式

<计算机视觉三> pytorch读取自己标定的数据集

<计算机视觉四> pytorch版yolov3网络搭建

<计算机视觉 五> 模型训练时候标签数据的变换

<计算机视觉 六> 深度学习目标检测模型的评估标准

<计算机视觉 七> 模型训练模块的代码

在标注好了数据集并且成功的将数据转换成pytorch框架可读的数据以后,我们需要一个网络模型用来训练这些数据。

以比较经典的yolov3网路为例,讲解下网络结构的的大体框架,yolo系列其实让人眼前一亮的目前而言就开山之作yolo1和精巧干练的yolov3至于后来变种yolov4主要特点在于使用一些数据增强的trick和csp网络结构,但是并没有多大的惊艳。yolov5的头部Focus网络和训练的时候调参技巧更加技巧化,以至于后来yolox并没有在v4和v5的版本上进行研究,而是采用yolov3作为一个baseline进行重新的设计和训练。

yolov3的算法有很多博主写的很详细了,本着不重复造轮子的思想这里就直接上代码讲解下pytorch实现的时候一些细节把,如果这里有看不懂的可以留言,后期会把整个项目代码上传GitHub

目前公认的网络组成是由于通用的骨干网络、颈部分支网络、和头部推理网络组成。

骨干网络重要发展:

LeNet 开山之作,用来学习下卷积神经网络和练习下代码实现还是不错的,结构简单清晰明了。

AlexNet 首次使用多GPU训练实现了CNN的工程落地。

VGGNet 惊艳的网络框架简单明了使用多层网络代替大尺寸网络。

GoogLeNet网络后来叫Inception系列取得不错的效果,但是由于网络结构过于复杂,实现过于复杂,但提出的网中网结构为后来的网络发展提供了一个研究方向。

ResNet全体起立何凯明大神的作品,简单暴力高效,至今被那创造性的思路折服,在pytorch框架中代码表现为符号 “+” 即特征层相加。

DenseNet从不同于ResNet的角度出发重复利用特征层,在pytorch中表现为代码torch.cat。

SeNet注意力机制,用的不多但是也是一个创新网络,优点是可以添加到现有的网络中,不过有时候效果并不那么显著还增加了计算量。

DarkNet53这个骨干网络没什么好讲的,就从创新来说一般,好像几乎yolo系列用的多。

transform系列 这个2020年开始火起来的有统一NLP和CNN的趋势吧,据说是个数据怪兽,样本少的话就别想了,从实际项目前期就几千张图片的场景来看,根本不够塞牙缝。

从此时开始骨干网络开始忘轻量化发展。比如mobileNet shuffleNet等后面有机会在介绍。

首先给出pytorch版本的Darknet53骨干网络实现:

#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@File    : backbone.py
@Time    : 2021/08/18 13:57:28
@Author  : XIA Yan
@Contact : 微信 lingyanlove
@Version : 0.1
@License : Apache License Version 2.0, January 2004
@Language: python3.8
@Desc    : 一些骨干网络
'''import torch
import torch.nn as nn# ++++++++++++++++++++++++++++++++++++++++++++++++++++
#    Darknet53 YoloV3 input ie. [batch, 3, 416, 416] #
# ++++++++++++++++++++++++++++++++++++++++++++++++++++def cbl(in_channels, out_channels, *args, **kwdargs):'''@description:YOLOv3 中CBL模块,即conv + batchNorm + LeakyRelU@Args:in_channel  : 输入层的通道数量out_channel : 输出层的通道数量@Return:返回经过CBL操作的网络'''return nn.Sequential(nn.Conv2d(in_channels, out_channels, *args, **kwdargs),nn.BatchNorm2d(out_channels),nn.LeakyReLU(0.1, inplace = True))class DarknetBlock(nn.Module):'''@description:Darknet53网络的1X1,3X3,參差网络模块@Args:in_channels: 模块的通道输入数量.@Return:经过残差的网络'''def __init__(self, channels):super().__init__()out_channels = channels//2self.conv1 = cbl(channels,  out_channels, kernel_size = 1)self.conv2 = cbl(out_channels, channels,  kernel_size = 3, padding = 1)def forward(self, x):return self.conv2(self.conv1(x)) + xclass Darknet53Backbone(nn.Module):'''@description:Darknet53的骨干网络使用的是CBL的YOLOV3的骨干网络@Args:layers:(list)骨干网中残差层块数量.block : (nn.Module)骨干网@Return:out   : tuple([[b, 256, 52, 52],[b, 256, 26, 26],[b, 256, 13, 13]]) '''def __init__(self, layers = [1, 2, 8, 8, 4], block = DarknetBlock):super().__init__()self.channels = []                   # 存放经过每个layers的通道[64, 128, 256, 512, 1024]self.selected_layers = [2,3,4]       # 选择最后3层用于后期的分类检测等操作self.in_channels = 32                # 设置初始的通道为32self.layers = nn.ModuleList()        # 创建一个List用于存网络# 输入图像[b, 3, 416, 416] -> [b, 32, 416, 416]self._pre_conv = cbl(in_channels = 3, out_channels= 32, kernel_size = 3, padding = 1)# 网络块操作self._make_layer(block, channels = 32 * 1, num_blocks = layers[0])self._make_layer(block, channels = 32 * 2, num_blocks = layers[1])self._make_layer(block, channels = 32 * 4, num_blocks = layers[2])self._make_layer(block, channels = 32 * 8, num_blocks = layers[3])self._make_layer(block, channels = 32* 16, num_blocks = layers[4])def _make_layer(self, block, channels, num_blocks, stride = 2):'''@description:创建layers = [1, 2, 8, 8, 4]的层结构@Args:block    :(nn.Module)网络块结构channels :(int)输入block的通道数量num_layuers:(int)block操作执行的次数stride   :(default = 2)下采样conv的stride值@Return:_make_layer函数本身没有返回,但函数会填充Darknet53Backbone的属性值'''layers_list = []# 1 首先进行下采样操作,这里和论文一样使用conv替代pooling操作downsample = cbl(self.in_channels, self.in_channels * 2, kernel_size = 3, stride = stride, padding = 1)layers_list.append(downsample)# 2 下采样后的网络进行残差模块处理, 每次通道数量就要 * 2self.in_channels = self.in_channels * 2layers_list += [block(self.in_channels) for _ in range(num_blocks)]# 将layers_list变成torch能识别的net结构后存入self.layers中self.channels.append(self.in_channels)self.layers.append(nn.Sequential(*layers_list))def forward(self, x):# 只返回Darknet的最后3个层convx  =  self._pre_conv(x)out = []for idx, layer in enumerate(self.layers):x = layer(x)if idx >=2:out.append(x)return tuple(out)# ++++++++++++++++++++++++++++++++++++++++++++++++++++
#    Darknet53 YoloV4 input ie.[batch, 3, 640, 640]  #
# ++++++++++++++++++++++++++++++++++++++++++++++++++++if __name__ == "__main__":if torch.cuda.is_available():torch.set_default_tensor_type('torch.cuda.FloatTensor')input_img = torch.rand(1,3,416,416)net = Darknet53Backbone()print(f"net的通道:{net.channels}")print(f"net的选择层:{net.selected_layers}")predict = net(input_img)for out in predict:print(out.shape)

骨干网络的还是比较简单,可以打印出网络结构查看,下面是yolov3的头部网络和推理结构

#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@File    : yolov3.py
@Time    : 2021/08/18 16:01:39
@Author  : XIA Yan
@Contact : 2440212215@qq.com
@Version : 0.1
@License : Apache License Version 2.0, January 2004
@Language: python3.8
@Desc    : YOLO v3的推理头文件部分
'''import torch
import torch.nn as nn
import torch.nn.functional as F
import numpy  as npfrom .backbone import Darknet53Backbone, cbl
from tools.utils import build_targetsclass PredictionModule(nn.Module):'''@description:YOLO 网络的推理头网络@Args:num_classes: 分类数量backbone:    骨干网络@Return:out1,out2,out3:3个网络输出层'''def __init__(self, num_classes = 80, backbone = Darknet53Backbone):super().__init__()self.layers = nn.ModuleList()                 # 用于存储3个DBL的网络self.backbone = backbone()self.net_channels = backbone().channels[2:]   # 选择骨干网络的最后3层 [256, 512, 1024]for idx, num_channels in enumerate(self.net_channels):out_channels  = num_channels              # DBL输出的通道数量[256, 512, 1024]if idx < 2:num_channels += num_channels//2       # 进入DBL的网络层数为 [384, 768, 1024]self._dbl(num_channels,out_channels)self.conv1  = cbl(512, 256, kernel_size = 1)self.conv2  = cbl(256, 128, kernel_size = 1)self.layer_out13 = self._conv_out(self.net_channels[0], num_classes)self.layer_out26 = self._conv_out(self.net_channels[1], num_classes)self.layer_out52 = self._conv_out(self.net_channels[2], num_classes)def _dbl(self, in_channels,out_channels):'''@description:YOLO v3推理头的 DBL网络结构 由多个(1×1 conv + 3×3 conv)的模块组成@Args:in_channels :(int)输入cbl的网络通道@Return:None'''layers_list = []pre_channels  =  in_channelstemp_channels = out_channels//2conv1x1_pre  = cbl(pre_channels, temp_channels, kernel_size = 1)conv3x3_1    = cbl(temp_channels, out_channels, kernel_size = 3, padding = 1)conv1x1_2    = cbl(out_channels, temp_channels, kernel_size = 1)conv3x3_2    = cbl(temp_channels, out_channels, kernel_size = 3, padding = 1)conv1x1_3    = cbl(out_channels, temp_channels, kernel_size = 1)layers_list.append(conv1x1_pre)        layers_list.append(conv3x3_1)        layers_list.append(conv1x1_2)        layers_list.append(conv3x3_2)        layers_list.append(conv1x1_3)        self.layers.append( nn.Sequential(*layers_list) )def _conv_out(self, in_channels, num_classes):'''@description:yolo层的输出 经过一个3×3的CBL操作后经过nn.Conv2d输出结果@Args:in_channels :(int)输入的通道数量@Return:返回网络输出层    '''return nn.Sequential(cbl(in_channels//2, in_channels, kernel_size = 3, padding = 1),nn.Conv2d(in_channels, 3 * (5 + num_classes),kernel_size= 1))def forward(self, x):# x shapes[1,3,416,416]# torch.Size([1, 256, 52, 52])  # 0# torch.Size([1, 512, 26, 26])  # 1# torch.Size([1, 1024, 13, 13]) # 2 outs = self.backbone(x)x    = self.layers[2](outs[2])    out1 = self.layer_out52(x)x    = F.interpolate(self.conv1(x), scale_factor = 2)   # 上采样层x    = torch.cat((outs[1], x), 1)                       # 在第2个通道链接层x    = self.layers[1](x)out2 = self.layer_out26(x)x    = F.interpolate(self.conv2(x), scale_factor = 2)   # 上采样层x    = torch.cat((outs[0], x), 1)                       # 在第2个通道链接层x    = self.layers[0](x)out3 = self.layer_out13(x)return out1,out2,out3class YoloLayer(nn.Module):'''@description:依据,class的数量和anchor,处理PredictionModule的3个层@Args:num_classes:(int)class的数量,coco默认80个@Return:out_put, total_loss, self.metrics'''def __init__(self, anchors, num_classes = 80,img_dim = 416):super().__init__()self.anchors     = anchors             # 获取当前层对应的anchorsself.num_classes = num_classesself.obj_scale   = 1                   # 正负样本中,正样本的比例self.noobj_scale = 100                 # 正负样本中,负样本的比例self.smoothl1    = nn.SmoothL1Loss()   # bbox中xywh的损失函数self.bce_loss    = nn.BCELoss()        # 分类损失和有无目标的损失函数self.metrics     = dict()              # 用list存放3层训练的评估 self.img_dim     = img_dim             # 训练图像的维度self.grid_size   = 0                   # 用于比较当前层的grid尺寸如果相同就不用重复计算后面修改后的anchordef compute_grid_offsets(self, grid_size, device):'''@description:根据Darnet53网络层的grid尺寸计算原anchor应该的缩放比例    @Args:grid_size :(int) yolo头推理层的gird尺寸 416输入的情况分别是13,26,52device    :(string)forward中输入的x设备名称,为了统一在一个设备上进行操作@Return:None'''self.grid_size = grid_sizeself.stride    = self.img_dim / self.grid_size       # 计算例如 416/grid 获取缩放比例# 使用meshgrid生成当前层的gird网格,并且存放在和forward中x相同的设备self.grid_y, self.grid_x = torch.meshgrid(torch.arange(grid_size).to(device),torch.arange(grid_size).to(device))# 修改原始层的anchor尺寸,并且存放在和forward中x相同的设备self.scaled_anchors = (self.anchors / self.stride).to(device)self.anchor_w       = self.scaled_anchors[:, 0:1].reshape((1, 3, 1, 1))self.anchor_h       = self.scaled_anchors[:, 1:2].reshape((1, 3, 1, 1))def forward(self, x, targets = None):'''@description:网络还是训练的数据入口,targets为None的时候就是推理,否则为训练@Args:x: (tensor[batch, 3*(5 + num_class), 13, 13]) PredictionModule网络的最后一层其中1个targets:(tensor[batch_id, label_id, x,y,w,h])数据类似,表示有4个batch图像其中 batch 0 有2个目标,且xywh是归一化后的数据[ [0, 1, 0.15, 0.06, 0.35, 0.26],  [0, 2, 0.21, 0.16, 0.86, 0.36],[1, 0, 0.41, 0.05, 0.25, 0.26],[2, 1, 0.15, 0.26, 0.36, 0.21],[3, 3, 0.15, 0.60, 0.34, 0.86],]@Return:out_put, total_loss, self.metrics'''# 1 获取当前输入x的相关信息 并转网络shape结构batch     = x.size(0)           # 获取batch数量grid_size = x.size(-1)          # 获取当前层的网格尺寸device    = x.device            # 获取x的设备# prediction shapes[b,3+num_cls,grid_size,grid_size] -> [b,3,grid_size,grid_size,5+num_cls]prediction = (x.view(batch, 3, 5 + self.num_classes, grid_size, grid_size)).permute(0, 1, 3, 4, 2).contiguous()# 2 获取输出x = torch.sigmoid(prediction[..., 0])          # center xy = torch.sigmoid(prediction[..., 1])          # center yw = prediction[..., 2]                         # 预测的bbox的宽度h = prediction[..., 3]                         # 预测的bbox的高度pred_conf = torch.sigmoid(prediction[..., 4])           # 有无目标conf的预测pred_cls  = torch.sigmoid(prediction[..., 5:])          # 每个格子预测的类别分类# 3 依据当前gird修改 anchor尺寸# if self.grid_size != grid_size:self.compute_grid_offsets(grid_size, device)# 4 计算box框的偏移,并且融合结果输出# BUG 即使不用torch.cuda.FloatTensor 使用下面的new依然触发使用cuda:0的bug# pred_boxes = prediction.new(prediction[..., :4].shape)  pred_boxes = torch.FloatTensor(prediction[..., :4].shape).to(device)  # 创建数据格式存放修正后的boxpred_boxes[..., 0] = x.detach() + self.grid_xpred_boxes[..., 1] = y.detach() + self.grid_ypred_boxes[..., 2] = torch.exp(w.detach()) * self.anchor_wpred_boxes[..., 3] = torch.exp(h.detach()) * self.anchor_hout_put = torch.cat((pred_boxes.reshape(batch, -1, 4) * self.stride,        # 将box坐标缩放回到基于416的图尺寸pred_conf.reshape(batch, -1, 1),pred_cls.reshape(batch, -1, self.num_classes)), dim = -1)if targets is None:    # 推理return out_put, 0, self.metricselse:                  # 训练iou_scores, class_mask, obj_mask, noobj_mask, tx, ty, tw, th, tcls = build_targets(pred_boxes = pred_boxes,pre_cls    = pred_cls,target     = targets,anchors    = self.scaled_anchors,)tconf  = obj_mask.float()       # 依据mask填充计算lossloss_x  = self.smoothl1(x[obj_mask], tx[obj_mask])loss_y  = self.smoothl1(y[obj_mask], ty[obj_mask])loss_w  = self.smoothl1(w[obj_mask], tw[obj_mask])loss_h  = self.smoothl1(h[obj_mask], th[obj_mask])loss_obj   = self.bce_loss(pred_conf[obj_mask], tconf[obj_mask])loss_noobj = self.bce_loss(pred_conf[noobj_mask], tconf[noobj_mask])loss_conf  = self.obj_scale * loss_obj + self.noobj_scale * loss_noobjloss_cls   = self.bce_loss(pred_cls[obj_mask], tcls[obj_mask])total_loss = loss_x + loss_y + loss_w + loss_h + loss_conf + loss_cls# 收集每层的评价数据Metricscls_acc      = class_mask[obj_mask].mean() * 100       # 计算当前层的精度conf_obj     = pred_conf[obj_mask].mean()              # 预测中有目标的位置的均值conf_noobj   = pred_conf[noobj_mask].mean()            # 预测中无目标的位置的均值conf50       = (pred_conf > 0.5).float()               # 预测有无目标的pred_conf > 0.5的位置iou50        = (iou_scores > 0.5).float()              # iou_scores > 0.5的位置iou75        = (iou_scores > 0.75).float()             # iou_scores > 0.75的位置detected_mask = conf50 * class_mask * tconf            # 预测有目标大于0.5位置、class分类对的位置、真实有目标位置的mask# precision是从预测数据出发,recall是从标记数据出发的统计# precision 预测iou>0.5,conf>0.5,class分类正确,obj_mask正目标都满足 / 预测conf>0.5的所有位置比例# recall50 预测iou>0.5,conf>0.5,class分类正确,obj_mask正目标都满足 / obj_mask正目标数量precision = torch.sum(iou50 * detected_mask) / (conf50.sum() + 1e-16)   recall50  = torch.sum(iou50 * detected_mask) / (obj_mask.sum() + 1e-16)recall75  = torch.sum(iou75 * detected_mask) / (obj_mask.sum() + 1e-16)self.metrics = {'loss':total_loss.detach().cpu().item(),'x_loss':loss_x.detach().cpu().item(),'y_loss':loss_y.detach().cpu().item(),'w_loss':loss_w.detach().cpu().item(),'h_loss':loss_h.detach().cpu().item(),'conf_loss':loss_conf.detach().cpu().item(),'class_loss':loss_cls.detach().cpu().item(),'class_acc':cls_acc.detach().cpu().item(),'recall50':recall50.detach().cpu().item(),'recall75':recall75.detach().cpu().item(),'precision':precision.detach().cpu().item(),'conf_obj':conf_obj.detach().cpu().item(),'conf_noobj':conf_noobj.detach().cpu().item(),'grid_size':grid_size,}return out_put, total_loss, self.metricsclass YoloV3(nn.Module):'''@description:YOLO V3的最后网络层,可以用于推理和训练@Args:num_classes :(int) 网络的类别创建的时候80区的是coco数据数量predictnet  :(nn.Module)头部网路@Return:'''def __init__(self, num_classes = 80, img_dim = 416, predictnet = PredictionModule, yololayer = YoloLayer):super().__init__()self.anchors = torch.tensor([ 10.,13., 16.,30., 33.,23.,30.,61., 62.,45., 59.,119.,116.,90., 156.,198., 373.,326.]).reshape(3,3,2)self.yolo_layers = []self.predictnet  = predictnet(num_classes)                           # Darknet最后的输出层是3个layerself.yololayer1  = yololayer(self.anchors[0],num_classes, img_dim)   # yolo推理层1 对应[13,13]self.yololayer2  = yololayer(self.anchors[1],num_classes, img_dim)   # yolo推理层1 对应[26,26]self.yololayer3  = yololayer(self.anchors[2],num_classes, img_dim)   # yolo推理层1 对应[52,52]def forward(self, x, targets = None):out1, out2, out3 = self.predictnet(x)yolo_out1, loss1, metrics1 = self.yololayer1(out1, targets)yolo_out2, loss2, metrics2 = self.yololayer2(out2, targets)yolo_out3, loss3, metrics3 = self.yololayer3(out3, targets)loss = loss1 + loss2 + loss3yolo_outputs = torch.cat((yolo_out1, yolo_out2, yolo_out3),dim = 1).detach().cpu()self.yolo_layers = [metrics1, metrics2, metrics3]return yolo_outputs if targets is None else (loss, yolo_outputs)#----保存和加载模型 ---def save_darknet_weights(self, path):'''保存yolo的网络参数'''print(f"正在保存网络结构到{path}中.........")torch.save(self.state_dict(),path)            # 这里不保存网络结构print("保存完毕!")def load_checkpoint(self,path):'''加载网络权重参数'''state_dict = torch.load(path)self.load_state_dict(state_dict)

本人整理了自己代码中的关于网络结构和实现的流程逻辑图

本图说明了骨干网络Darknet各层的输出后如果经过yolo推理头网络进行特征提取,yolov3使用3个特征层,每个层有3个anchor box (后来的free anchor已经不需预设框,在部署的时候也方便许多)。小特征预测大目标,大特征预测小目标。

下一章介绍如何之前的pytorch Dataset模块产生的数据具体如何生成上图能够训练的数据。

鼠标点击下载     项目源代码免费下载地址

<计算机视觉一> 使用标定工具标定自己的目标检测

<计算机视觉二> labelme标定的数据转换成yolo训练格式

<计算机视觉三> pytorch读取自己标定的数据集

<计算机视觉四> pytorch版yolov3网络搭建

<计算机视觉 五> 模型训练时候标签数据的变换

<计算机视觉 六> 深度学习目标检测模型的评估标准

<计算机视觉 七> 模型训练模块的代码

<计算机视觉四> pytorch版yolov3网络搭建相关推荐

  1. 史上最详细的Pytorch版yolov3代码中文注释详解(四)

    史上最详细的Pytorch版yolov3代码中文注释详解(一):https://blog.csdn.net/qq_34199326/article/details/84072505 史上最详细的Pyt ...

  2. WIN10 +pytorch版yolov3训练自己数据集

    pytorch版yolov3训练自己数据集 目录 1. 环境搭建 2. 数据集构建 3. 训练模型 4. 测试模型 5. 评估模型 6. 可视化 7. 高级进阶-网络结构更改 1. 环境搭建 将git ...

  3. 1 PyTorch版YOLOv3 代码中文注释 之 训练 train.py test.py detect.py

    文章目录 PyTorch版YOLOv3 代码中文注释 1. 相关链接: 2. 代码结构: 3. train.py 3.1. train.py 中包含的主要功能 4. test.py 4.1. test ...

  4. python调用yolov3模型,pytorch版yolov3训练自己的数据(数据,代码,预训练模型下载链接)...

    1.数据预处理 准备图片数据(JPEGImages),标注文件(Annotations),以及划分好测试集训练集的索引号(ImageSets) 修改代码中voc_label.py文件中的路径以及类别, ...

  5. (四)OpenStack---M版---双节点搭建---Glance安装和配置

    ↓↓↓↓↓↓↓↓视频已上线B站↓↓↓↓↓↓↓↓ >>>>>>传送门 1.创建glance数据库 2.获得 admin 凭证来获取只有管理员能执行的命令的访问权限 3 ...

  6. 大创学习记录(四)之yolov3代码学习

    PyTorch-YOLOv3项目训练与代码学习 借助从零开始的PyTorch项目理解YOLOv3目标检测的实现 PyTorch 对于PyTorch就不用多说了,目前最灵活.最容易掌握的深度学习库,它有 ...

  7. pytorch实现Yolov3网络结构

    #基于torch的yolov3网络结构Darknet53实现 最近一段时间在研究目标检测,先从yolov3看起.本文讲下如何使用pytorch实现yolov3网络结构中的DarkNet53网络结构. ...

  8. 华为自研凌霄四核内芯+四信号放大器:249元华为路由WS5200四核版正式开售

    [TechWeb]作为一年365天,24小时不断输出Wi-Fi信号的路由器,在现代家庭生活中担任着越来越重要的角色.随着老百姓家中智能设备数量成倍增加,它们可以是大到电视,也可以是小到灯泡;这些设备都 ...

  9. 目标检测-基于Pytorch实现Yolov3(1)- 搭建模型

    原文地址:https://www.cnblogs.com/jacklu/p/9853599.html 本人前段时间在T厂做了目标检测的项目,对一些目标检测框架也有了一定理解.其中Yolov3速度非常快 ...

最新文章

  1. 《评人工智能如何走向新阶段》后记(再续2)
  2. Python 报错 SyntaxError: invalid syntax 解决方法
  3. QThreadPool Class的翻译
  4. 第一百二十六期:代码以外的生存之道,献给每位入了坑的码农
  5. 06. 从尾到头打印链表
  6. 信息学奥赛C++语言: 素数个数
  7. 算术基本定理“质数分解唯一性的证明”:古典方法与现代方法
  8. 数据分析师熬夜整理:最全「零售业」数据指标和使用技巧
  9. batocera整合包_模擬器作業系統RetroPie更新至4.6,支援Raspberry Pi 4、新增NeoGeo CD模擬功能...
  10. GO 计算所有并发任务的总时间 WaitGroup
  11. lamp环境搭建之配置apache与fpm方式的php
  12. C语言推荐书籍从入门到进阶带你走上大牛之路
  13. scrcpy---Android投屏神器(使用教程)
  14. 如何计算机械能增加量,探讨优化验证机械能守恒定律实验中动能增加量的计算方法...
  15. 最佳搜索引擎蜘蛛工具
  16. 大二暑期第四周学习总结
  17. IOS TableViewCell分割线设置和隐藏多余cell
  18. 03-图像分割效果评估
  19. 阿里巴巴Java开发手册及Java代码规约扫描eclipse插件
  20. 大鹏教育视频下载(手动操作)

热门文章

  1. mysql root密码登陆,修改mysql的root密码后还不能登陆怎么办?
  2. 监督学习、无监督学习和半监督学习区别
  3. 成为华尔街金融巨鳄第三课: Pandas2:学会使用Pandas-DataFrame
  4. Python版跳跳方块小游戏源代码,跳跳益智游戏代码
  5. 计算机管理系统功能模块,仓库管理系统功能模块详解
  6. js 定时网页点击_前端面试题熬夜吐血(js进阶篇)
  7. 适合女性的4个计算机相关岗位,薪资待遇好,未来前景广阔
  8. 知识图谱第3享:数据生命周期
  9. 飞凌嵌入式Android测试
  10. 妇产科护理学重点知识