CV学习笔记-MobileNet
MobileNet
文章目录
- MobileNet
- 1. MobileNet概述
- 2. 深度可分离卷积(depthwise separable convolution)
- 2.1 深度可分离卷积通俗理解
- 2.2 深度可分离卷积对于参数的优化
- 3. MobileNet网络结构
- 4. 代码实现
- 4.1 卷积块
- 4.2 深度可分离卷积块
- 4.3 MobileNet定义
- 4.4 完整代码
1. MobileNet概述
网络专注于移动端或者嵌入式设备中的轻量级CNN,相比于传统卷积神经网络,在准确率小幅度降低的前提下大大减少模型参数与运算量。
传统卷积与DW卷积(Depthwise Conv)的差异,在传统卷积中,每个卷积核的channel与输入特征矩阵的channel相等(每个卷积核都会与输入特征矩阵的每一个维度进行卷积运算),输出特征矩阵channel等于卷积核的个数。而在DW卷积中,每个卷积核的channel都是等于1的(每个卷积核只负责输入特征矩阵的一个channel,卷积核的个数=输入特征矩阵的channel数=输出特征矩阵的channel数)
MobileNet模型是Google针对手机等嵌入式设备提出的一种轻量级的深层神经网络,其使用的核心思想便是深度可分离卷积 depthwise separable convolution
2. 深度可分离卷积(depthwise separable convolution)
2.1 深度可分离卷积通俗理解
传统的三通道卷积过程如下:
那么深度可分离卷积能用到轻量级的网络中,保证效率减少参数量,其具体是如何巧妙设计优化的,下图为深度可分离卷积的运作过程。
深度可分离卷积分为两个部分,Depthwise Convolution (深度卷积)、Pointwise Convolution(点卷积),这是两个不同的卷积过程,传统三通道卷积的过程是一个卷积核的厚度有三层,每一层与输入的feature map的每一层做加权求和,从而生成输出的一个通道,故输出通道数取决于卷积核的数量,卷积核的通道数等同于输入feature map的通道数(对齐)
而Depthwise Convolution不同,其卷积核的厚度只有1,对于输入的feature map(特征图谱)的每一个通道,都有一个不同的厚度为1的卷积核相对应(卷积核数量与输入通道数对应),每个卷积核都只对对应通道的feature map做卷积操作,这样得到的每一个通道的卷积操作得到一个1通道的feature map,这样深度卷积之后的输出通道数与输入通道数一致。下图中绿色、红色、黄色表示的不同的通道数为1的卷积核。
点卷积(Pointwise Convolution)是采用1×11\times11×1大小的卷积核(此时的卷积核是传统卷积核,其通道数与输入通道数相同)分别遍历输入的所有通道,得到的输出通道取决于卷积核的个数,点卷积与传统卷积方式相同,只是卷积核使用1×11\times11×1,起到一个改变通道数的作用,直观意义上讲就是加厚输出的feature map,其实际的意义在于由于深度卷积的方式对于特征提取不够明显,再通过点卷积进行一些信息补偿,在保证参数量减少的情况下,尽可能的让网络的效果保持一个可观的水平。
2.2 深度可分离卷积对于参数的优化
举例说明优化的效果,由于MobileNet是用于嵌入式设备等受限的设备上的网络,其参数肯定是大幅度降低的。
有下列场景:
使用3×33\times33×3大小的卷积层,输入通道数为16,输出通道数为32.
使用传统卷积的方式,需要32个3×33\times33×3的卷积核对16个通道中的每一层数据进行卷积计算,最后得到32个输出通道的feature map,所需要的参数量为:
16×32×3×3=460816\times 32\times 3\times 3=4608 16×32×3×3=4608
采用深度可分离卷积,由于输入的通道数为16,那么采用16个3×33\times33×3大小的卷积核对16个通道的feature map分别卷积,得到一个16通道的输出feature map,为了得到所需要的32通道的输出,采用点卷积的方式,使用32个1×11\times11×1大小的卷积核遍历16个通道的输入feature map,那么参数量为:
16×3×3+16×32×1×1=65616\times 3\times 3+16\times 32\times 1\times 1=656 16×3×3+16×32×1×1=656
通过上述实验对比,参数量确实大大减少。
注意:深度可分离卷积指的是深度卷积(Depthwise Conv)+点卷积(Pointwise Conv),而并不是一个dw(Depthwise的缩写)就是一个深度可分离卷积,这个概念混淆度很高
3. MobileNet网络结构
一个深度可分离卷积的结构如下所示:
首先对输入做深度卷积(Depthwise Conv),深度卷积的特点是是卷积核的个数与处理的输入通道数一致同时每个卷积核通道数都是1,每个1通道卷积核去卷积输入feature map里的一个通道的数据,导致深度卷积处理之后输入与输出的通道数总是不变的。
深度卷积之后就是BN层,BN层为Batch Normalization,对数据做归一化处理,再通过激活函数,接下来是一个1×11\times11×1的Conv层,其就是点卷积的层,使用1×11\times11×1的卷积核进行卷积操作,改变通道数,再进行归一化和激活输出。
BN的作用以及应用过程已经在笔者的博文《CV学习笔记-Inception》中详细介绍,不再赘述。
MobileNet的网络结构图如下所示
在此不进行逐层分析,仅对初始几层进行分析,后面的读者可以自行推导,计算过程一致。
首先输入为224×224×3224\times 224\times 3224×224×3,卷积核的shape为3×3×3×323\times 3\times 3\times 323×3×3×32,通过卷积核的shape,能够看出本次卷积操作采用的是一个传统的卷积计算,卷积核的通道数为3,个数为32,那么得到的输出为112×112×32112\times 112\times 32112×112×32(stride步长为2),此处的通道数32与卷积采用的卷积核个数32对应,之后经过Conv dw层,这个是深度卷积层,dw即Depthwise,输入feature map为112×112×32112\times 112\times 32112×112×32,所用卷积核shape为3×3×323\times 3\times 323×3×32注意与上面一层的卷积层相区别,少了一个维度,因为每一个卷积核的通道数为1,每个1通道卷积核只需要卷积feature map中的一个通道的数据,故经过深度卷积之后的输出通道数不变,输出的feature map为112×112×32112\times 112\times 32112×112×32,然后通过一个点卷积层,卷积核shape为1×1×32×641\times 1\times 32\times 641×1×32×64,即使用64个1×1×1×321\times 1\times 1 \times 321×1×1×32的卷积核进行卷积操作,点卷积卷积的方式与传统的卷积相同,只是在尺寸上采用的1×11\times 11×1的卷积核,用点卷积的方式改变通道数,输出的feature map shape为112×112×64112\times 112\times 64112×112×64,接下来就可以留给读者推算了,深度可分离卷积部分已经作出了分析。
4. 代码实现
4.1 卷积块
代码按照传统的Conv-BN-Relu组合拳,进行卷积块的定义padding采用same方式
def _conv_block(inputs, filters, kernel=(3, 3), strides=(1, 1)):x = Conv2D(filters, kernel,padding='same',use_bias=False,strides=strides,name='conv1')(inputs)x = BatchNormalization(name='conv1_bn')(x)return Activation(relu6, name='conv1_relu')(x)
4.2 深度可分离卷积块
深度可分离卷积分为深度卷积和点卷积,x = DepthwiseConv2D([params])
即为深度卷积块的定义,使用的是DepthwiseConv2D()
,在深度卷积完成BN+Relu后,紧接着接上了一个点卷积模块,x = Conv2D(pointwise_conv_filters,(1, 1))
,使用1×11\times 11×1卷积核来改变通道数。
def _depthwise_conv_block(inputs, pointwise_conv_filters,depth_multiplier=1, strides=(1, 1), block_id=1):x = DepthwiseConv2D((3, 3),padding='same',depth_multiplier=depth_multiplier,strides=strides,use_bias=False,name='conv_dw_%d' % block_id)(inputs)x = BatchNormalization(name='conv_dw_%d_bn' % block_id)(x)x = Activation(relu6, name='conv_dw_%d_relu' % block_id)(x)x = Conv2D(pointwise_conv_filters, (1, 1),padding='same',use_bias=False,strides=(1, 1),name='conv_pw_%d' % block_id)(x)x = BatchNormalization(name='conv_pw_%d_bn' % block_id)(x)return Activation(relu6, name='conv_pw_%d_relu' % block_id)(x)
4.3 MobileNet定义
按照MobileNet的网络结构,将其复现成python程序,整合的就是上面定义的卷积模块和深度可分离卷积模块。(预训练权重文件可以在网络上下载)
def MobileNet(input_shape=[224,224,3],depth_multiplier=1,dropout=1e-3,classes=1000):img_input = Input(shape=input_shape)# 224,224,3 -> 112,112,32x = _conv_block(img_input, 32, strides=(2, 2))# 112,112,32 -> 112,112,64x = _depthwise_conv_block(x, 64, depth_multiplier, block_id=1)# 112,112,64 -> 56,56,128x = _depthwise_conv_block(x, 128, depth_multiplier,strides=(2, 2), block_id=2)# 56,56,128 -> 56,56,128x = _depthwise_conv_block(x, 128, depth_multiplier, block_id=3)# 56,56,128 -> 28,28,256x = _depthwise_conv_block(x, 256, depth_multiplier,strides=(2, 2), block_id=4)# 28,28,256 -> 28,28,256x = _depthwise_conv_block(x, 256, depth_multiplier, block_id=5)# 28,28,256 -> 14,14,512x = _depthwise_conv_block(x, 512, depth_multiplier,strides=(2, 2), block_id=6)# 14,14,512 -> 14,14,512x = _depthwise_conv_block(x, 512, depth_multiplier, block_id=7)x = _depthwise_conv_block(x, 512, depth_multiplier, block_id=8)x = _depthwise_conv_block(x, 512, depth_multiplier, block_id=9)x = _depthwise_conv_block(x, 512, depth_multiplier, block_id=10)x = _depthwise_conv_block(x, 512, depth_multiplier, block_id=11)# 14,14,512 -> 7,7,1024x = _depthwise_conv_block(x, 1024, depth_multiplier,strides=(2, 2), block_id=12)x = _depthwise_conv_block(x, 1024, depth_multiplier, block_id=13)# 7,7,1024 -> 1,1,1024x = GlobalAveragePooling2D()(x)x = Reshape((1, 1, 1024), name='reshape_1')(x)x = Dropout(dropout, name='dropout')(x)x = Conv2D(classes, (1, 1),padding='same', name='conv_preds')(x)x = Activation('softmax', name='act_softmax')(x)x = Reshape((classes,), name='reshape_2')(x)inputs = img_inputmodel = Model(inputs, x, name='mobilenet_1_0_224_tf')model_name = 'mobilenet_1_0_224_tf.h5'model.load_weights(model_name)return model
4.4 完整代码
本代码完成了一个图片的识别,图片如下,可以重命名为elephant.jpg输入网络运行。
#-------------------------------------------------------------#
# MobileNet的网络部分
#-------------------------------------------------------------#
import warnings
import numpy as np# from keras.preprocessing import imagefrom keras.models import Model
from keras.layers import DepthwiseConv2D,Input,Activation,Dropout,Reshape,BatchNormalization,GlobalAveragePooling2D,GlobalMaxPooling2D,Conv2D
from keras.applications.imagenet_utils import decode_predictions
from keras.utils import image_utils as image
from keras import backend as Kdef MobileNet(input_shape=[224,224,3],depth_multiplier=1,dropout=1e-3,classes=1000):img_input = Input(shape=input_shape)# 224,224,3 -> 112,112,32x = _conv_block(img_input, 32, strides=(2, 2))# 112,112,32 -> 112,112,64x = _depthwise_conv_block(x, 64, depth_multiplier, block_id=1)# 112,112,64 -> 56,56,128x = _depthwise_conv_block(x, 128, depth_multiplier,strides=(2, 2), block_id=2)# 56,56,128 -> 56,56,128x = _depthwise_conv_block(x, 128, depth_multiplier, block_id=3)# 56,56,128 -> 28,28,256x = _depthwise_conv_block(x, 256, depth_multiplier,strides=(2, 2), block_id=4)# 28,28,256 -> 28,28,256x = _depthwise_conv_block(x, 256, depth_multiplier, block_id=5)# 28,28,256 -> 14,14,512x = _depthwise_conv_block(x, 512, depth_multiplier,strides=(2, 2), block_id=6)# 14,14,512 -> 14,14,512x = _depthwise_conv_block(x, 512, depth_multiplier, block_id=7)x = _depthwise_conv_block(x, 512, depth_multiplier, block_id=8)x = _depthwise_conv_block(x, 512, depth_multiplier, block_id=9)x = _depthwise_conv_block(x, 512, depth_multiplier, block_id=10)x = _depthwise_conv_block(x, 512, depth_multiplier, block_id=11)# 14,14,512 -> 7,7,1024x = _depthwise_conv_block(x, 1024, depth_multiplier,strides=(2, 2), block_id=12)x = _depthwise_conv_block(x, 1024, depth_multiplier, block_id=13)# 7,7,1024 -> 1,1,1024x = GlobalAveragePooling2D()(x)x = Reshape((1, 1, 1024), name='reshape_1')(x)x = Dropout(dropout, name='dropout')(x)x = Conv2D(classes, (1, 1),padding='same', name='conv_preds')(x)x = Activation('softmax', name='act_softmax')(x)x = Reshape((classes,), name='reshape_2')(x)inputs = img_inputmodel = Model(inputs, x, name='mobilenet_1_0_224_tf')model_name = 'mobilenet_1_0_224_tf.h5'model.load_weights(model_name)return modeldef _conv_block(inputs, filters, kernel=(3, 3), strides=(1, 1)):x = Conv2D(filters, kernel,padding='same',use_bias=False,strides=strides,name='conv1')(inputs)x = BatchNormalization(name='conv1_bn')(x)return Activation(relu6, name='conv1_relu')(x)def _depthwise_conv_block(inputs, pointwise_conv_filters,depth_multiplier=1, strides=(1, 1), block_id=1):x = DepthwiseConv2D((3, 3),padding='same',depth_multiplier=depth_multiplier,strides=strides,use_bias=False,name='conv_dw_%d' % block_id)(inputs)x = BatchNormalization(name='conv_dw_%d_bn' % block_id)(x)x = Activation(relu6, name='conv_dw_%d_relu' % block_id)(x)x = Conv2D(pointwise_conv_filters, (1, 1),padding='same',use_bias=False,strides=(1, 1),name='conv_pw_%d' % block_id)(x)x = BatchNormalization(name='conv_pw_%d_bn' % block_id)(x)return Activation(relu6, name='conv_pw_%d_relu' % block_id)(x)def relu6(x):return K.relu(x, max_value=6)def preprocess_input(x):x /= 255.x -= 0.5x *= 2.return xif __name__ == '__main__':model = MobileNet(input_shape=(224, 224, 3))img_path = 'elephant.jpg'img = image.load_img(img_path, target_size=(224, 224))x = image.img_to_array(img)x = np.expand_dims(x, axis=0)x = preprocess_input(x)print('Input image shape:', x.shape)preds = model.predict(x)print(np.argmax(preds))print('Predicted:', decode_predictions(preds,1)) # 只显示top1
实验输出:
相关文章:

CV学习笔记-MobileNet
MobileNet 文章目录MobileNet1. MobileNet概述2. 深度可分离卷积(depthwise separable convolution)2.1 深度可分离卷积通俗理解2.2 深度可分离卷积对于参数的优化3. MobileNet网络结构4. 代码实现4.1 卷积块4.2 深度可分离卷积块4.3 MobileNet定义4.4 完…...

C++进阶——继承
C进阶——继承 1.继承的概念及定义 面向对象三大特性:封装、继承、多态。 概念: 继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特 性的基础上进行扩展,增加功能,这…...

数据结构---单链表
专栏:数据结构 个人主页:HaiFan. 专栏简介:从零开始,数据结构!! 单链表前言顺序表的缺陷链表的概念以及结构链表接口实现打印链表中的元素SLTPrintphead->next!NULL和phead!NULL的区别开辟空间SLTNewNod…...

redis数据结构的底层实现
文章目录一.引言二.redis的特点三.Redis的数据结构a.字符串b.hashc.listd.sete.zset(有序集合)一.引言 redis是一个开源的使用C语言编写、支持网络、可基于内存亦可持久化的日志型、key-value的NoSQL数据库。 通常使用redis作为缓存中间件来降低数据库的压力,除此…...

【JavaSE】复习(进阶)
文章目录1.final关键字2.常量3.抽象类3.1概括3.2 抽象方法4. 接口4.1 接口在开发中的作用4.2类型和类型之间的关系4.3抽象类和接口的区别5.包机制和import5.1 包机制5.2 import6.访问控制权限7.Object7.1 toString()7.2 equals()7.3 String类重写了toString和equals8.内部类8.1…...

Java 主流日志工具库
日志系统 java.util.logging (JUL) JDK1.4 开始,通过 java.util.logging 提供日志功能。虽然是官方自带的log lib,JUL的使用确不广泛。 JUL从JDK1.4 才开始加入(2002年),当时各种第三方log lib已经被广泛使用了JUL早期存在性能问题&#x…...

产品经理有必要考个 PMP吗?(含PMP资料)
现在基本上做产品的都有一个PMP证件,从结果导向来说,不对口不会有这么大范围的人来考,但是需要因地制宜,在公司内部里,标准程序并不流畅,产品和项目并不规范,关系错综复杂。 而产品经理的职能又…...

什么是原型、原型链?原型和原型链的作用
1、ES6之前,继承都用构造函数来实现;对象的继承,先申明一个对象,里面添加实例成员<!DOCTYPE html> <html><head><meta charset"utf-8" /><title></title></head><body><script…...

条件期望4
条件期望例题----快排算法的分析 快速排序算法的递归定义如下: 有n个数(n≥2n\geq 2n≥2), 一开始随机选取一个数xix_ixi, 并将xix_ixi和其他n-1个数进行比较, 记SiS_iSi为比xix_ixi小的元素构成的集合, Siˉ\bar{S_i}Siˉ为比xix_ixi大的元素构成的集合, 然后分…...

网络协议分析(2)判断两个ip数据包是不是同一个数据包分片
一个节点收到两个IP包的首部如下:(1)45 00 05 dc 18 56 20 00 40 01 bb 12 c0 a8 00 01 c0 a8 00 67(2)45 00 00 15 18 56 00 b9 49 01 e0 20 c0 a8 00 01 c0 a8 00 67分析并判断这两个IP包是不是同一个数据报的分片&a…...

6.2 负反馈放大电路的四种基本组态
通常,引入交流负反馈的放大电路称为负反馈放大电路。 一、负反馈放大电路分析要点 如图6.2.1(a)所示电路中引入了交流负反馈,输出电压 uOu_OuO 的全部作为反馈电压作用于集成运放的反向输入端。在输入电压 uIu_IuI 不变的情况下,若由于…...

MySQL进阶之锁
锁是计算机中协调多个进程或线程并发访问资源的一种机制。在数据库中,除了传统的计算资源竞争之外,数据也是一种提供给许多用户共享的资源,如何保证数据并发访问的一致性和有效性是数据库必须解决堆的一个问题,锁冲突也是影响数据…...

【Mac 教程系列】如何在 Mac 上破解带有密码的 ZIP 压缩文件 ?
如何使用 fcrackzip 在 Mac 上破解带有密码的 ZIP 压缩文件? 用 markdown 格式输出答案。 在 Mac 上破解带有密码的 ZIP 压缩文件 使用解压缩软件,如The Unarchiver,将文件解压缩到指定的文件夹。 打开终端,输入 zip -er <zipfile> &…...

【Acwing 周赛复盘】第92场周赛复盘(2023.2.25)
【Acwing 周赛复盘】第92场周赛复盘(2023.2.25) 周赛复盘 ✍️ 本周个人排名:1293/2408 AC情况:1/3 这是博主参加的第七次周赛,又一次体会到了世界的参差(这次周赛记错时间了,以为 19:15 开始&…...

L1-087 机工士姆斯塔迪奥
在 MMORPG《最终幻想14》的副本“乐欲之所瓯博讷修道院”里,BOSS 机工士姆斯塔迪奥将会接受玩家的挑战。 你需要处理这个副本其中的一个机制:NM 大小的地图被拆分为了 NM 个 11 的格子,BOSS 会选择若干行或/及若干列释放技能,玩家…...

本周大新闻|索尼PS VR2立项近7年;传腾讯将引进Quest 2
本周大新闻,AR方面,传立讯精密开发苹果初代AR头显,第二代低成本版将交给富士康;iOS 16.4代码曝光新的“计算设备”;EM3推出AR眼镜Stellar Pro;努比亚将在MWC2023推首款AR眼镜。VR方面,传闻腾讯引…...

aws console 使用fargate部署aws服务快速跳转前端搜索栏
测试过程中需要在大量资源之间跳转,频繁的点击不如直接搜索来的快,于是写了一个搜索框方便跳转。 前端的静态页面可以通过s3静态网站托管实现,但是由于中国区需要备案的原因,可以使用ecs fargate部署 步骤如下: 编写…...

Redis实战之Redisson使用技巧详解
一、摘要什么是 Redisson?来自于官网上的描述内容如下!Redisson 是一个在 Redis 的基础上实现的 Java 驻内存数据网格客户端(In-Memory Data Grid)。它不仅提供了一系列的 redis 常用数据结构命令服务,还提供了许多分布…...

SQLAlchemy
文章目录SQLAlchemy介绍SQLAlchemy入门使用原生sql使用orm外键关系一对多关系多对多关系基于scoped_session实现线程安全简单表操作实现方案CRUDFlask 集成 sqlalchemySQLAlchemy 介绍 SQLAlchemy是一个基于Python实现的ORM框架。该框架建立在 DB API之上,使用关系…...

【Linux学习笔记】8.Linux yum 命令和apt 命令
前言 本章介绍Linux的yum命令和apt命令。 Linux yum 命令 yum( Yellow dog Updater, Modified)是一个在 Fedora 和 RedHat 以及 SUSE 中的 Shell 前端软件包管理器。 基于 RPM 包管理,能够从指定的服务器自动下载 RPM 包并且安装…...

windows服务器实用(4)——使用IIS部署网站
windows服务器实用——IIS部署网站 如果把windows服务器作为web服务器使用,那么在这个服务器上部署网站是必须要做的事。在windows服务器上,我们一般使用IIS部署。 假设此时前端给你一个已经完成的网站让你部署在服务器上,别人可以在浏览器…...

Random(二)什么是伪共享?@sun.misc.Contended注解
目录1.背景简介2.伪共享问题3.问题解决4.JDK使用示例1.背景简介 我们知道,CPU 是不能直接访问内存的,数据都是从高速缓存中加载到寄存器的,高速缓存又有 L1,L2,L3 等层级。在这里,我们先简化这些复杂的层级…...

Linux解压压缩
打包tar首先我们得提一下专门用于打包文件的命令——tartar用于备份文件,打包多个文件或者目录,也可以用于还原被打包的文件假设打包目录test下的文件 tar -cvf test.tar ./test 假设打包目录test下的文件,并用gzip命令将包压缩 tar -zcvf test.tar ./te…...

JavaSe第3次笔记
1.String str "hello";字符串类型。 2.两个字符串类型相加意思是拼接,类似于c语言里面的strcat函数。 3.整型变成字符串类型: int a 10; String str String. valueOf(a); 4.当字符串和其他类型进行相加的时候,结果就是字符串。(不完全…...

非人工智能专业怎样从零开始学人工智能?
人工智能(Artificial Intelligence,AI)是指让机器具有类似人类智能的能力,包括感知、理解、推理、学习、规划、决策、创造等多个方面。人工智能研究涉及到计算机科学、数学、物理学、心理学、哲学等多个领域,旨在模拟和…...

MyBatis之增、删、查、改
目录 前言 一、配置MyBatis开发环境 1.1 创建数据库和表 1.2 添加框架支持 1.3 创建目录结构 1.4 配置数据库连接 1.5 配置MyBatis中的XML文件路径 二、添加业务代码 2.1 查询数据库操作 2.1.1 添加实体类 2.1.2 添加mapper接口 2.1.3 在xml中实现mapper接口 2.1.…...

死磕Spring,什么是SPI机制,对SpringBoot自动装配有什么帮助
文章目录如果没时间看的话,在这里直接看总结一、Java SPI的概念和术语二、看看Java SPI是如何诞生的三、Java SPI应该如何应用四、从0开始,手撸一个SPI的应用实例五、SpringBoot自动装配六、Spring SPI机制与Spring Factories机制做对比七、这里是给我自…...

因果推断10--一种大规模预算约束因果森林算法(LBCF)
论文:A large Budget-Constrained Causal Forest Algorithm 论文:http://export.arxiv.org/pdf/2201.12585v2.pdf 目录 0 摘要 1 介绍 2 问题的制定 3策略评价 4 方法 4.1现有方法的局限性。 4.2提出的LBCF算法 5验证 5.1合成数据 5.2离线生…...

Linux基础命令-df显示磁盘的使用情况
文章目录 文章目录 df 命令介绍 语法格式 基本参数 参考实例 1)以人类可读形式显示磁盘空间的使用情况 2)显示磁盘的inode信息 3)显示磁盘和文件系统类型 4)指定显示文件系统 5)显示所有磁盘空间中的内容 …...

如何使用goquery进行HTML解析以及它的源码分析和实现原理
目录 goquery 是什么 goquery 能用来干什么 goquery quick start 玩转goquery.Find() 查找多个标签 Id 选择器 Class 选择器 属性选择器 子节点选择器 内容过滤器 goquery 源码分析 图解源码 总结 goquery 简介 goquery是一款基于Go语言的HTML解析库,…...