首页
壁纸
留言板
友链
更多
统计归档
Search
1
TensorBoard:训练日志及网络结构可视化工具
12,588 阅读
2
主板开机跳线接线图【F_PANEL接线图】
7,063 阅读
3
Linux使用V2Ray 原生客户端
6,168 阅读
4
移动光猫获取超级密码&开启公网ipv6
4,734 阅读
5
NVIDIA 显卡限制功率
3,138 阅读
好物分享
实用教程
linux使用
wincmd
学习笔记
mysql
java学习
nginx
综合面试题
大数据
网络知识
linux
放码过来
python
javascript
java
opencv
蓝桥杯
leetcode
深度学习
开源模型
相关知识
数据集和工具
模型轻量化
语音识别
计算机视觉
杂七杂八
硬件科普
主机安全
嵌入式设备
其它
bug处理
登录
/
注册
Search
标签搜索
好物分享
学习笔记
linux
MySQL
nvidia
typero
内网穿透
webdav
vps
java
cudann
gcc
cuda
树莓派
CNN
图像去雾
ssh安全
nps
暗通道先验
阿里云
jupiter
累计撰写
354
篇文章
累计收到
71
条评论
首页
栏目
好物分享
实用教程
linux使用
wincmd
学习笔记
mysql
java学习
nginx
综合面试题
大数据
网络知识
linux
放码过来
python
javascript
java
opencv
蓝桥杯
leetcode
深度学习
开源模型
相关知识
数据集和工具
模型轻量化
语音识别
计算机视觉
杂七杂八
硬件科普
主机安全
嵌入式设备
其它
bug处理
页面
壁纸
留言板
友链
统计归档
搜索到
354
篇与
的结果
2022-01-07
Yolov5s:Yolov5sv6.0网络结构分析与实现
1.参考网络结构图(v5.0的)2. 配置文件解析原始配置文件yolov5s.yaml# YOLOv5 by Ultralytics, GPL-3.0 license # Parameters nc: 80 # number of classes depth_multiple: 0.33 # model depth multiple width_multiple: 0.50 # layer channel multiple anchors: - [10,13, 16,30, 33,23] # P3/8 - [30,61, 62,45, 59,119] # P4/16 - [116,90, 156,198, 373,326] # P5/32 # YOLOv5 v6.0 backbone backbone: # [from, number, module, args] [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 [-1, 3, C3, [128]], [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 [-1, 6, C3, [256]], [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 [-1, 9, C3, [512]], [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 [-1, 3, C3, [1024]], [-1, 1, SPPF, [1024, 5]], # 9 ] # YOLOv5 v6.0 head head: [[-1, 1, Conv, [512, 1, 1]], [-1, 1, nn.Upsample, [None, 2, 'nearest']], [[-1, 6], 1, Concat, [1]], # cat backbone P4 [-1, 3, C3, [512, False]], # 13 [-1, 1, Conv, [256, 1, 1]], [-1, 1, nn.Upsample, [None, 2, 'nearest']], [[-1, 4], 1, Concat, [1]], # cat backbone P3 [-1, 3, C3, [256, False]], # 17 (P3/8-small) [-1, 1, Conv, [256, 3, 2]], [[-1, 14], 1, Concat, [1]], # cat head P4 [-1, 3, C3, [512, False]], # 20 (P4/16-medium) [-1, 1, Conv, [512, 3, 2]], [[-1, 10], 1, Concat, [1]], # cat head P5 [-1, 3, C3, [1024, False]], # 23 (P5/32-large) [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) ]配置文件解析Model( (model): Sequential( (0): Conv(3,32,6,2,2) # 3x640x640-->32x320x320 (1): Conv(32,64,3,2) # 32x320x320-->64x160x160 (2): C3(64,64) # 64x160x160-->64x160x160 (3): Conv(64,128,3,2) # 64x160x160-->128x80x80 #P3 (4): C3(128,128) # 128x80x80-->128x80x80 (5): Conv(128,256,3,2) # 128x80x80-->256x40x40 #P4 (6): C3(256,256) # 256x40x40-->256x40x40 (7): Conv(256,512,3,2) # 256x40x40-->512x20x20 #P5 (8): SPP(512,512,[5, 9, 13]) # 512x20x20-->512x20x20 (9): C3(512,512) # 512x20x20-->512x20x20 #P6 (10): Conv(512,256,1,1) # 512x20x20-->256x20x20 (11): nn.Upsample(None, 2, 'nearest') # 256x20x20-->256x40x40 (12): Concat() # [x,p4]==>512x40x40 (13): C3(512,256) # 512x40x40-->256x40x40 (14): Conv(256,128) # 256x40x40-->128x40x40 (15): nn.Upsample(None, 2, 'nearest') # 128x40x40-->128x80x80 (16): Concat() # [x,p3]==>256x80x80 (17): C3(256,128) # 256x80x80-->128x80x80 #out1 (18): Conv(128,128,3,2) # 128x80x80-->128x40x40 (19): Concat() # [x,p4]==>384x40x40 (20): C3(384,256) # 384x40x40-->256x40x40 #out2 (21): Conv(256,256,3,2) # 256x40x40-->256x20x20 (22): Concat() # [x,p5]==>768x20x20 (23): C3(768,512) # 768x20x20 -->512x20x20 #out3 (24): Detect( (0): Conv2d(128, 255) # 128x80x80-->((cls_num+4+1)*anchor_num)x80x80 #out1_detect==>[3, 80, 80, 85] (1): Conv2d(256, 255) # 256x40x40-->((cls_num+4+1)*anchor_num)x40x40 #out2_detect==>[3, 40, 40, 85] (2): Conv2d(512, 255) # 512x20x20-->((cls_num+4+1)*anchor_num)x20x20 #out3_detect==>[3, 20, 20, 85] ) ) )3.代码实现3.1 公共基本块import torch import torch.nn as nn import warnings class Conv(nn.Module): # 标准卷积 def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True): # ch_in, ch_out, kernel, stride, padding, groups super().__init__() self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p), groups=g, bias=False) self.bn = nn.BatchNorm2d(c2) self.act = nn.SiLU() if act is True else (act if isinstance(act, nn.Module) else nn.Identity()) def forward(self, x): return self.act(self.bn(self.conv(x))) def forward_fuse(self, x): return self.act(self.conv(x)) def forward_fuse(self, x): return self.act(self.conv(x)) class Bottleneck(nn.Module): # 标准bottleneck def __init__(self, c1, c2, shortcut=True, g=1, e=0.5): # ch_in, ch_out, shortcut, groups, expansion super().__init__() c_ = int(c2 * e) # hidden channels self.cv1 = Conv(c1, c_, 1, 1) self.cv2 = Conv(c_, c2, 3, 1, g=g) self.add = shortcut and c1 == c2 def forward(self, x): return x + self.cv2(self.cv1(x)) if self.add else self.cv2(self.cv1(x)) class C3(nn.Module): # CSP Bottleneck with 3 convolutions def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): # ch_in, ch_out, number, shortcut, groups, expansion super().__init__() c_ = int(c2 * e) # hidden channels self.cv1 = Conv(c1, c_, 1, 1) self.cv2 = Conv(c1, c_, 1, 1) self.cv3 = Conv(2 * c_, c2, 1) # act=FReLU(c2) self.m = nn.Sequential(*[Bottleneck(c_, c_, shortcut, g, e=1.0) for _ in range(n)]) # self.m = nn.Sequential(*[CrossConv(c_, c_, 3, 1, g, 1.0, shortcut) for _ in range(n)]) def forward(self, x): return self.cv3(torch.cat((self.m(self.cv1(x)), self.cv2(x)), dim=1)) class SPPF(nn.Module): # Spatial Pyramid Pooling - Fast (SPPF) layer for YOLOv5 by Glenn Jocher def __init__(self, c1, c2, k=5): # equivalent to SPP(k=(5, 9, 13)) super().__init__() c_ = c1 // 2 # hidden channels self.cv1 = Conv(c1, c_, 1, 1) self.cv2 = Conv(c_ * 4, c2, 1, 1) self.m = nn.MaxPool2d(kernel_size=k, stride=1, padding=k // 2) def forward(self, x): x = self.cv1(x) with warnings.catch_warnings(): warnings.simplefilter('ignore') # suppress torch 1.9.0 max_pool2d() warning y1 = self.m(x) y2 = self.m(y1) return self.cv2(torch.cat([x, y1, y2, self.m(y2)], 1)) class Concat(nn.Module): # 沿维度连接张量列表 def __init__(self, dimension=1): super().__init__() self.d = dimension def forward(self, x): return torch.cat(x, self.d) def autopad(k, p=None): # kernel, padding # 计算然卷积结果与输入具有相同大小的padding if p is None: p = k // 2 if isinstance(k, int) else [x // 2 for x in k] # auto-pad return p3.2 backboneclass Yolov5sV6Backbone(nn.Module): def __init__(self): super(Yolov5sV6Backbone,self).__init__() self.backbone_part1 = nn.Sequential( Conv(3,32,6,2,2), # 0 Conv(32,64,3,2), # 1 C3(64,64), #2 Conv(64,128,3,2) #3 ) self.backbone_part2 = nn.Sequential( C3(128,128), # 4_1 Conv(128,256,3,2) # 5 ) self.backbone_part3 = nn.Sequential( C3(256,256), # 6 Conv(256,512,3,2) # 7 ) self.backbone_part4 = nn.Sequential( C3(512,512), # 8 SPPF(512,512,5), # 9 ) def forward(self,x): p3 = self.backbone_part1(x) p4 = self.backbone_part2(p3) p5 = self.backbone_part3(p4) p6 = self.backbone_part4(p5) return p3,p4,p5,p6调用测试backbone = Yolov5sV6Backbone() fake_input = torch.rand(1,3,640,640) p3,p4,p5,p6 = backbone(fake_input) print(p3.shape,p4.shape,p5.shape,p6.shape)torch.Size([1, 128, 80, 80]) torch.Size([1, 256, 40, 40]) torch.Size([1, 512, 20, 20]) torch.Size([1, 512, 20, 20])3.3 headclass Yolov5sV6Head(nn.Module): def __init__(self): super(Yolov5sV6Head,self).__init__() self.head_part1 = nn.Sequential( Conv(512,256,1,1), # 10 nn.Upsample(None, 2, 'nearest') # 11 ) self.head_concat1 =Concat() # 12 self.head_part2 = nn.Sequential( C3(512,256), # 13 Conv(256,128), # 14 nn.Upsample(None, 2, 'nearest') # 15 ) self.head_concat2 = Concat() # 16 self.head_out1 = C3(256,128) # 17 # 128x80x80 self.head_part3 = Conv(128,128,3,2) # 18 self.head_concat3 = Concat() # 19 self.head_out2 = C3(384,256) # 20 self.head_part4 = Conv(256,256,3,2) # 21 self.head_concat4 = Concat() # 22 self.head_out3 = C3(768,512) # 23 # 512x40x40 def forward(self,p3,p4,p5,x): x = self.head_part1(x) x = self.head_concat1([x,p4]) x = self.head_part2(x) x = self.head_concat2([x,p3]) out1 = self.head_out1(x) x = self.head_part3(out1) x = self.head_concat3([x,p4]) out2 = self.head_out2(x) x = self.head_part4(out2) x = self.head_concat4([x,p5]) out3 = self.head_out3(x) return out1,out2,out3调用测试backbone = Yolov5sV6Backbone() head = Yolov5sV6Head() fake_input = torch.rand(1,3,640,640) p3,p4,p5,p6 = backbone(fake_input) out1,out2,out3 = head(p3,p4,p5,p6) print(out1.shape,out2.shape,out3.shape)3.4 detect 部分class Yolov5sV6Detect(nn.Module): stride = None # strides computed during build def __init__(self, nc=80, anchors=(), ch=[128,256,512], inplace=True): # detection layer super(Yolov5sV6Detect,self).__init__() self.nc = nc # number of classes self.no = nc + 5 # number of outputs per anchor self.nl = len(anchors) # number of detection layers self.na = len(anchors[0]) // 2 # number of anchors self.grid = [torch.zeros(1)] * self.nl # init grid self.anchor_grid = [torch.zeros(1)] * self.nl # init anchor grid self.register_buffer('anchors', torch.tensor(anchors).float().view(self.nl, -1, 2)) # shape(nl,na,2) self.m = nn.ModuleList(nn.Conv2d(x, self.no * self.na, 1) for x in ch) # output conv self.inplace = inplace # use in-place ops (e.g. slice assignment) def forward(self, x): z = [] # inference output for i in range(self.nl): x[i] = self.m[i](x[i]) # conv bs, _, ny, nx = x[i].shape # x(bs,255,20,20) to x(bs,3,20,20,85) x[i] = x[i].view(bs, self.na, self.no, ny, nx).permute(0, 1, 3, 4, 2).contiguous() if not self.training: # inference if self.grid[i].shape[2:4] != x[i].shape[2:4]: self.grid[i], self.anchor_grid[i] = self._make_grid(nx, ny, i) y = x[i].sigmoid() if self.inplace: y[..., 0:2] = (y[..., 0:2] * 2 - 0.5 + self.grid[i]) * self.stride[i] # xy y[..., 2:4] = (y[..., 2:4] * 2) ** 2 * self.anchor_grid[i] # wh else: # for YOLOv5 on AWS Inferentia https://github.com/ultralytics/yolov5/pull/2953 xy = (y[..., 0:2] * 2 - 0.5 + self.grid[i]) * self.stride[i] # xy wh = (y[..., 2:4] * 2) ** 2 * self.anchor_grid[i] # wh y = torch.cat((xy, wh, y[..., 4:]), -1) z.append(y.view(bs, -1, self.no)) return x if self.training else (torch.cat(z, 1), x) def _make_grid(self, nx=20, ny=20, i=0): d = self.anchors[i].device if check_version(torch.__version__, '1.10.0'): # torch>=1.10.0 meshgrid workaround for torch>=0.7 compatibility yv, xv = torch.meshgrid([torch.arange(ny, device=d), torch.arange(nx, device=d)], indexing='ij') else: yv, xv = torch.meshgrid([torch.arange(ny, device=d), torch.arange(nx, device=d)]) grid = torch.stack((xv, yv), 2).expand((1, self.na, ny, nx, 2)).float() anchor_grid = (self.anchors[i].clone() * self.stride[i]) \ .view((1, self.na, 1, 1, 2)).expand((1, self.na, ny, nx, 2)).float() return grid, anchor_grid调用测试anchors = [ [10,13, 16,30, 33,23], [30,61, 62,45, 59,119], [116,90, 156,198, 373,326] ] backbone = Yolov5sV6Backbone() head = Yolov5sV6Head() detect = Yolov5sV6Detect(nc=80,anchors=anchors) fake_input = torch.rand(1,3,640,640) p3,p4,p5,p6 = backbone(fake_input) out1,out2,out3 = head(p3,p4,p5,p6) out1,out2,out3 = detect([out1,out2,out3]) print(out1.shape,out2.shape,out3.shape)torch.Size([1, 3, 80, 80, 85]) torch.Size([1, 3, 40, 40, 85]) torch.Size([1, 3, 20, 20, 85])3.5 整体组装class Yolov5sV6(nn.Module): def __init__(self,nc=80,anchors=()): super(Yolov5sV6,self).__init__() self.backbone = Yolov5sV6Backbone() self.head = Yolov5sV6Head() self.detect = Yolov5sV6Detect(nc,anchors) def forward(self,x): p3,p4,p5,p6 = self.backbone(x) out1,out2,out3 = self.head(p3,p4,p5,p6) out1,out2,out3 = self.detect([out1,out2,out3]) return out1,out2,out3调用测试anchors = [ [10,13, 16,30, 33,23], [30,61, 62,45, 59,119], [116,90, 156,198, 373,326] ] yolov5s = Yolov5sV6(nc=80,anchors=anchors) fake_input = torch.rand(1,3,640,640) out1,out2,out3 = yolov5s(fake_input) print(out1.shape,out2.shape,out3.shape)torch.Size([1, 3, 80, 80, 85]) torch.Size([1, 3, 40, 40, 85]) torch.Size([1, 3, 20, 20, 85])4.模型复杂度分析模型名Input模型大小全精度模型大小半精度参数量FLOPSbackbone640x64026.0MB13.1MB3.80M4.42GFLOPShead640x64011.5MB5.78MB3.00M2.79GFLOPSdetect640x640897KB450KB0.23M0.37GFLOPSYolov5s640x64026.9M13.5M7.03M7.58GFLOPS参考资料https://github.com/ultralytics/yolov5YOLOv5代码详解(common.py部分)Yolov5从入门到放弃(一)---yolov5网络架构YOLOV5网络结构
2022年01月07日
2,116 阅读
0 评论
0 点赞
2022-01-05
Subsonic:使用VPS自建私有云音乐服务
1.简介Subsonic是一个免费且基于Web的媒体流媒体,用Java编写,适用于Linux、MacOS和Windows平台。使用Subsonic,你可以从家用计算机或任何面向公众的计算机流式传输音乐,并通过网络浏览器随时随地聆听音乐,因此你无需将音乐与弹性同步或Syncthing等文件同步应用程序同步。Subsonic功能:支持MP3、OGG、AAC以及通过HTTP流式传输的任何其他音频或视频格式适用于任何支持网络的媒体播放器,如Winamp、iTunes、XMMS、VLC、MusicMatch和Windows Media Player。专辑艺术展示,即时播放列表,即时转码。适用于Mac、Windows、Android、iPhone、Windows Phone和桌面应用的移动应用,Android应用支持离线播放。收听播客,分配评级,添加评论和创建播放列表。与朋友和家人分享音乐。流视频(高级功能)。2.在Ubuntu 上安装Subsonic2.1 安装java环境sudo apt update sudo apt install openjdk-8-jre当前Subsonic版本与Java 11不兼容,如果之前在Ubuntu 18.04上安装了Java 11,那么需要运行以下命令来选择默认的Java版本sudo update-alternatives --config java2.2 安装Subsonic接下来,使用以下命令下载Subsonic deb软件包,该命令将下载6.1.6版,可以在Subsonic网站的下载页面上查看最新版本,如果有新版本,只需将6.1.6替换为新版本号即可:wget https://s3-eu-west-1.amazonaws.com/subsonic-public/download/subsonic-6.1.6.deb用dpkg安装它:sudo dpkg -i subsonic-6.1.5.deb安装后,Subsonic守护程序将自动启动2.3 管理Subsonic# 可以通过以下命令检查其状态: systemctl status subsonic # 如果它没有运行,那么你可以手动启动它: sudo systemctl start subsonic # 并在系统启动时启用自动启动: sudo systemctl enable subsonic2.4 访问测试并进行相关设置登录默认情况下,subsonic侦听0.0.0.0:4040,这意味着它接受来自本地网络和Internet的请求。如果在本地Ubuntu计算机上安装了Subsonic,请在浏览器中输入http://localhost:4040访问Subsonic Web界面:如果在面向Internet的Ubuntu服务器上安装了Subsonic,请在浏览器中输入http://your-server-ip:4040访问Subsonic Web界面:默认用户名和密码是admin修改语言修改媒体文件夹请注意,用户必须可以访问该文件夹添加文件夹后,单击“立即扫描媒体文件夹”按钮,将可以在“Index”页面中收听音乐:2.5 更改启动用户默认情况下,Subsonic进程以root用户身份运行,出于安全原因,应该将其更改为普通用户,这可以通过编辑/etc/default/subsonic文件来完成:sudo vim /etc/default/subsonic找到以下行:SUBSONIC_USER=root将root更改为自己的用户帐户,如jupiter:SUBSONIC_USER=jupiter保存并关闭文件,然后重新启动subsonic守护程序以使更改生效:sudo systemctl restart subsonic2.在Centos 上安装Subsonic参考:https://zhuanlan.zhihu.com/p/46767211参考资料使用VPS自建私有云音乐服务–Subsonic在Ubuntu 18.04系统上安装Subsonic的方法
2022年01月05日
1,679 阅读
0 评论
0 点赞
2021-12-30
端侧CNN参数压缩和加速(模型轻量化)技术
1.简介1.1 应用背景与云端的GPU设备相比,端侧的设备在成本和功耗方面具有明显优势。但在端侧的设备具有更小的内存,更小的算力,这对移动端的模型带来了更高的要求,端测模型需要满足模型尺寸小、计算复杂度低、电池耗电量低、部署灵活等条件。设备类型设备名显存/内存浮点算力GPURTX 308010G29117 GFLOPSGPURTX 2080 Ti11G16626 GFLOPS端侧设备树莓派4B2G/4G/8G13.5 GFLOPS1.2 模型压缩和加速介绍模型压缩和加速是两个不同的话题,压缩重点在于减少网络参数量,加速则侧重在降低计算复杂度、提升并行能力等。有时候压缩并不一定能带来加速的效果,有时候又是相辅相成的。模型压缩和加速可以从多个角度来优化。算法层压缩加速。这个维度主要在算法应用层,也是大多数算法工程师的工作范畴。主要包括结构优化(如矩阵分解、分组卷积、小卷积核等)、量化与定点化、模型剪枝、模型蒸馏等。框架层加速。这个维度主要在算法框架层,比如tf-lite、NCNN、MNN等。主要包括编译优化、缓存优化、稀疏存储和计算、NEON指令应用、算子优化等硬件层加速。这个维度主要在AI硬件芯片层,目前有GPU、FPGA、ASIC等多种方案,各种TPU、NPU就是ASIC这种方案,通过专门为深度学习进行芯片定制,大大加速模型运行速度。本文将重点针对算法层压缩加速进行介绍。2.算法层压缩加速2.1 轻量架构设计/结构优化2.1.1 分组卷积在分组卷积(Group convolution)中,输入特征图尺寸为 $H \times W \times c_1$,将输入特征图按照通道数分成 $g$组,则每组输入特征图的尺寸为$H \times W \times \frac{c_1}{g}$,对应的卷积核尺寸为 $h_1 \times w_1 \times \frac{c_1}{g}$ ,每组输出特征图尺寸为$H \times W \times \frac{c_2}{g}$,将$g$组结果拼接(concat),得到最终输出特征图尺寸为 $H \times W \times c_2$ ,因此分组卷积层的参数量为:$$ h_1 \times w_1 \times \frac{c_1}{g} \times \frac{c_2}{g} \times g = h_1 \times w_1 \times c_1 \times c_2 \times \frac{1}{g} $$即分组卷积的参数量是标准卷积的$\frac{1}{g}$。2.1.2 MobileNet结构MobileNetv1 论文该论文最大的创新点是,提出了深度可分离卷积(depthwise separable convolution)。同时作者还使用了ReLU6激活函数来替代ReLU激活函数。标准卷积在标准卷积中,输入特征图尺寸为 $H \times W \times c_1$,卷积核尺寸为 $h_1 \times w_1 \times c_1$ ,输出特征图尺寸为 $H \times W \times c_2$ ,标准卷积层的参数量为:$$ (h_1 \times w_1 \times c_1) \times c_2 $$运算量约为(忽略偏置计算):$$ w \times h \times c \times w_1 \times h_1 \times c_1 $$深度可分离卷积深度可分离卷(Depthwise separable convolution)积由逐通道卷积和逐点卷积两个部分组合而成,用来提取特征feature map。相比常规的卷积操作,其参数数量和运算成本比较低。逐通道卷积逐通道卷积(Depthwise Convolution)的一个卷积核负责一个通道,一个通道只被一个卷积核卷积。该阶段等价于$g=c_1$的组卷积,其参数量为:$$ h_1 \times w_1 \times 1 \times c_1 $$计算量为:$$ h_1 \times w_1 \times c_1 \times h_2 \times w_2 $$逐点卷积逐点卷积(Pointwise Convolution)的运算与常规卷积运算非常相似,它的卷积核的尺寸为 1×1×M,M为上一层的通道数。所以这里的卷积运算会将上一步的map在深度方向上进行加权组合,生成新的Feature map。有几个卷积核就有几个输出Feature map该阶段按普通卷积的方式计算可得参数量为:$$ 1 \times 1 \times c_1 \times c_2 $$计算量为:$$ h_2 \times w_2 \times c_1 \times c_2 $$总参数量与计算量分析则总的参数量为:$$ h_1 \times w_1 \times c_2 + c_1 \times c_2 $$即深度可分离卷积的参数量是标准卷积的$$ \frac{h_1 \times w_1 \times c_1 + c_1 \times c_2}{(h_1 \times w_1 \times c_1) \times c_2} = \frac{1}{c_2}+\frac{1}{h_1 \times w_1} $$总的计算量为:$$ h_1 \times w_1 \times c_1 \times h_2 \times w_2 +h_2 \times w_2 \times c_1 \times c_2 $$即深度可分离卷积的的计算量是标准卷积的:$$ \frac{h_1 \times w_1 \times c_1 \times h_2 \times w_2 +h_2 \times w_2 \times c_1 \times c_2}{h_1 \times w_1 \times c_1 \times h_2 \times w_2} = \frac{1}{c_2}+\frac{1}{h_1 \times w_1} $$ReLU6$$ ReLU = max(0,x) \\ ReLU6 = max(max(0,x),6) $$上图左边是普通的ReLU,对于大于0的值不进行处理,右边是ReLU6,当输入的值大于6的时候,返回6,relu6“具有一个边界”。作者认为ReLU6作为非线性激活函数,在低精度计算下具有更强的鲁棒性。(这里所说的“低精度”,我看到有人说不是指的float16,而是指的定点运算(fixed-point arithmetic))MobileNetv2 论文有人在实际使用深度可分离卷积的时候, 发现深度卷积部分的卷积核比较容易训废掉:训完之后发现深度卷积训出来的卷积核有不少是空的(参数都为0了),作者认为这是ReLU激活函数的锅。因此,作者将V2在V1的基础上,引入了Inverted Residuals(倒残差模块)和Linear Bottlenecks。简单来说,就是当低维信息映射到高维,经过ReLU后再映射回低维时,若映射到的维度相对较高,则信息变换回去的损失较小;若映射到的维度相对较低,则信息变换回去后损失很大,如下图所示。因此,作者认为对低维度做ReLU运算,很容易造成信息的丢失。而在高维度进行ReLU运算的话,信息的丢失则会很少。另外一种解释是,高维信息变换回低维信息时,相当于做了一次特征压缩,会损失一部分信息,而再进过ReLU后,损失的部分就更加大了。作者为了这个问题,就将ReLU替换成线性激活函数。Inverted Residuals/倒残差模块残差模块:输入首先经过$1 \times 1$的卷积进行压缩,然后使用$3 \times 3$的卷积进行特征提取,最后在用$1 \times 1$的卷积把通道数变换回去。整个过程是“压缩-卷积-扩张”。这样做的目的是减少$3 \times 3$模块的计算量,提高残差模块的计算效率。倒残差模块:输入首先经过$1 \times 1$的卷积进行通道扩张,然后使用$3 \times 3$的depthwise卷积,最后使用$1 \times 1$的pointwise卷积将通道数压缩回去。整个过程是“扩张-卷积-压缩”。为什么这么做呢?因为depthwise卷积不能改变通道数,因此特征提取受限于输入的通道数,所以将通道数先提升上去。文中的扩展因子为6。Linear Bottlenecks这个模块是为了解决上面提出的那个低维-高维-低维的问题,即将最后一层的ReLU替换成线性激活函数,而其他层的激活函数依然是ReLU6。如下图所示。当stride=1时,输入首先经过$1 \times 1$的卷积进行通道数的扩张,此时激活函数为ReLU6;然后经过$3 \times 3$的depthwise卷积,激活函数是ReLU6;接着经过$1 \times 1$的pointwise卷积,将通道数压缩回去,激活函数是linear;最后使用shortcut,将两者进行相加。而当stride=2时,由于input和output的特征图的尺寸不一致,所以就没有shortcut了。MobileNetv3 论文mobilenet V3并没有惊艳的结构提出,主要是一些tricks的应用和结合。v3版本结合了v1的深度可分离卷积、v2的Inverted Residuals和Linear Bottleneck、h-swish非线性变换、SE模块,利用NAS(神经结构搜索)来搜索网络的配置和参数。引入SE结构在bottlenet结构中加入了SE结构,并且放在了depthwise filter之后,如下图:因为SE结构会消耗一定的时间,所以作者在含有SE的结构中,将expansion layer的channel变为原来的1/4,这样作者发现,即提高了精度,同时还没有增加时间消耗。修改尾部结构在mobilenetv2中,在avg pooling之前,存在一个$1 \times 1$的卷积层,目的是提高特征图的维度,更有利于结构的预测,但是这其实带来了一定的计算量了,所以这里作者修改了,将其放在avg pooling的后面,首先利用avg pooling将特征图大小由$7 \times 7$降到了$1 \times 1$,降到$1 \times 1$后,然后再利用$1 \times 1$提高维度,这样就减少了$7 \times 7=49$倍的计算量。为了进一步的降低计算量,作者直接去掉了前面纺锤型卷积的$3 \times 3$以及$1 \times 1$卷积,进一步减少了计算量,就变成了如上图第二行所示的结构,作者将其中的$3 \times 3$以及$1 \times 1$去掉后,精度并没有得到损失。这里降低了大约15ms的速度。修改channel数量修改头部卷积核channel数量,mobilenet v2中使用的是$32 \times 3 \times 3$,作者发现,其实32可以再降低一点,所以这里作者改成了16,在保证了精度的前提下,降低了3ms的速度。非线性变换(新激活函数)的改变谷歌提出了一种新出的激活函数swish x(如下) 能有效改进网络精度,但是计算量太大了。$$ swish(x)=x \cdot \sigma(x) = x \cdot sigmoid(x) $$作者使用h-swish来近似替代sigmoid,进行了速度优化,具体如下:$$ h-swish(x)=x \frac{ReLU6(x+3)}{6} $$利用ReLU有几点好处:1.可以在任何软硬件平台进行计算2.量化的时候,它消除了潜在的精度损失,使用h-swish替换swish,在量化模式下回提高大约15%的效率,另外,h-swish在深层网络中更加明显。2.1.3 IGC结构IGCv1 论文它的重点在于提出了一个新颖的构建块--交错组卷积。交错组卷积它是一种交错组卷积块的堆叠结构。每个块包含两个组卷积: 第一次组卷积核第二次组卷积,所谓组卷积就是在卷积时有两个分组。第一次组卷积是把输入通道划分为L个组,每个组包含M个通道,然后将L个分组卷积的结果拼接在一起得到新的输入其仍然有LxM个通道之后打乱顺序第二次组卷积划分了M个组,每个组包含L个通道,且这L个通道来自第一次分组卷积时的不同组。同时第一次卷积做的是空间域卷积,第二次做的是逐点卷积。比起普通卷积,在网络参数量和计算复杂度不变的同时,使得网络变得更宽了。IGCv1 vs XceptionIGCV是第一个空间域的$3 \times 3$Group Conv,之后接第二个$1 \times 1$逐点卷积来融合通道信息,乍一看和Xception很像,可以说Xception就是IGCV的一种极端情况,Group数和Channel数相等的情况。作者列举了$L=1$以及$M=1$的极端情况,也就对应着普通卷积以及Xception的极端组卷积结果当然是IGCv1最好(摊手),从图上可以看到当每组只有2个通道的时候,效果是最好的,也就是文中最后IGCv1的结构了。最后还补充了两次组卷积次序可以交换,并不影响结果;可以将$3 \times 3$卷积分解成$3 \times 1$和$1 \times 3$,可以更加提高效率。IGCv2 论文IGCv2的主要创新点也就是在IGCv1的基础上,对于block里第二次组卷积再进行一次IGC。即使用多个稀疏卷积来替换原本比较稠密的卷积。IGCv1 vs IGCv2 IGCv1的结构如上图,可以看出第二次组卷积的时候,每一组的通道数仍然很多,文中的话就是比较dense, 因此想到对于每一组再进行IGC,这样就能进一步提升计算的效率了,也就是IGCv2,将每个组的普通卷积替换成交错组卷积,具体可见下图,IGCv3 论文IGCV3的主要创新点对IGCV2的结构进行延伸,引入低秩分组卷积来代替原本的分组卷积。就是先用1x1Group Pointwise Covolution升维,再3x3的组卷积,再通过1x1Group Pointwise Covolution进行降维,主要结构如下图与MobileNetV2的对比,基本上就是1x1卷积改成了1x1的组卷积。IGCV3在IGCV2的基础上融合了MobileNetV2的主要结构,并且使用更狠的低秩稀疏分组卷积,在整体结构上和MobileNetV2十分接近,核心依然是在稀疏分组卷积以及排序操作,虽然性能比MobileNetV2有些许提升,但整体的创新性略显不足。2.1.4 Inception结构Inception结构作用原理:Inception的作用就是替代了人工确定卷积层中过滤器的类型或者是否创建卷积层和池化层,让网络自己学习它具体需要什么参数。Inception-v1 论文提高网络最简单粗暴的方法就是提高网络的深度和宽度,即增加隐层和以及各层神经元数目。但这种简单粗暴的方法存在一些问题:会导致更大的参数空间,更容易过拟合需要更多的计算资源网络越深,梯度容易消失,优化困难(这时还没有提出BN时,网络的优化极其困难)Inception-v1的目标就是,提高网络计算资源的利用率,在计算量不变的情况下,提高网络的宽度和深度。首先看第一个结构,有四个通道,有$1 \times 1、3 \times 3、5 \times 5$卷积核,该结构有几个特点:采用大小不同的卷积核,意味着感受野的大小不同,就可以得到不同尺度的特征。采用比较大的卷积核即$5 \times 5$,因为有些相关性可能隔的比较远,用大的卷积核才能学到此特征。但是这个结构有个缺点,$5 \times 5$的卷积核的计算量太大。那么作者想到了第二个结构,用$1 \times 1$的卷积核进行降维。这个1*1的卷积核,它的作用就是:降低维度,减少计算瓶颈增加网络层数,提高网络的表达能力那么在具体的卷积神经网络中,Inception应该放在哪里,作者的建议,在底层保持传统卷积不变,在高层使用Inception结构。Inception-v2 论文其主要思想在于提出了Batch Normalization,其次才是稍微改进了一下Inception,把Inception-v1中$5 \times 5$的卷积用2个$3 \times 3$的卷积替换。这样做法有两个优点:保持相同感受野的同时减少参数加强非线性的表达能力Inception-v3 论文主要从分解卷积核尺寸、使用辅助分类器、改变降低特征图尺寸的方式三个方面进行改进(使用辅助分类器与轻量化设计关系不大)。分解卷积核尺寸分解为对称的小的卷积核,(参考上面的Inception-v2)分解为不对称的卷积核分解为不对称的卷积核就是将$n \times n$的卷积核替换成 $1 \times n$ 和$n \times 1$ 的卷积核堆叠,计算量又会降低。但是该方法在大维度的特征图上表现不好,在特征图12-20维度上表现好。不对称分解方法有几个优点:节约了大量的参数增加一层非线性,提高模型的表达能力可以处理更丰富的空间特征,增加特征的多样性改变降低特征图尺寸的方式在传统的卷积神经网络的中,当有pooling时(pooling层会大量的损失信息),会在之前增加特征图的厚度(就是双倍增加滤波器的个数),通过这种方式来保持网络的表达能力,但是计算量会大大增加。作者对传统的池化方式进行了如下的改进:有两个通道,一个是卷积层,一个是pooling层,两个通道生成的特征图大小一样,concat在一起即可。Inception-v4 [论文]()本文的主要思想是将Inception与很火的ResNet结合,与轻量化设计的关系不大。2.1.5 Xception结构Xception 论文Xception 是 Google 继 Inception 后提出的对 Inception-v3 的另一种改进。作者认为,通道之间的相关性 与 空间相关性 最好要分开处理。采用 Separable Convolution(极致的 Inception 模块)来替换原来 Inception-v3中的卷积操作。结构的变形过程如下:在 Inception 中,特征可以通过$1 \times 1$卷积, $3 \times 3$卷积, $5 \times 5$ 卷积,pooling 等进行提取,Inception 结构将特征类型的选择留给网络自己训练,也就是将一个输入同时输给几种提取特征方式,然后做 concat 。Inception-v3的结构图如下:对 Inception-v3 进行简化,去除 Inception-v3 中的 avg pool 后,输入的下一步操作就都是 $1 \times 1$卷积:提取$1 \times 1$卷积的公共部分:Xception(极致的 Inception):先进行普通卷积操作,再对$1 \times 1$卷积后的每个channel分别进行$3 \times 3$卷积操作,最后将结果 concat:2.1.6 ResNeXt结构ResNeXt 论文ResNeXt是ResNet和Inception的结合体,不同于Inception v4的是,ResNext不需要人工设计复杂的Inception结构细节,而是每一个分支都采用相同的拓扑结构,ResNeXt的本质是分组卷积。所有Inception模型都具有一个重要的性质——都是遵循 拆分-变换-合并(split-transform-merge) 的设计策略。Inception模型中block的输入会先被拆分成若干低维编码(使用$1 \times 1$卷积实现),然后经过多个不同的滤波器(如$3 \times 3$、$5 \times 5$等)进行转换,最后通过沿通道维度串联的方式合并。这种设计策略希望在保持网络计算复杂度相当低的前提下获取与包含大量且密集的层的网络具有相同的表示能力。但是,Inception模型实现起来很麻烦,它包含一系列复杂的超参——每个变换的滤波器的尺寸和数量都需要指定,不同阶段的模块也需要定制。太多的超参数大多的影响因素,如何将Inception模型调整到适合不同的数据集/任务变得很不明晰。简化Inception基于此,作者的思想是每个结构使用相同的拓扑结构,那么这时候的Inception(这里简称简化Inception)表示为:$$ y = \sum^{C}_{i=1}T_i(x) $$其中 $C$ 是简Inception的基数(Cardinality),$T_i$是任意的变换,例如一系列的卷积操作等。Inception简化前后的对比如下图所示:ResNeXt再结合强大的残差网络,我们得到的便是完整的ResNeXt,也就是在简化Inception中添加一条short-cut,表示为:$$ y = \sum^{C}_{i=1}T_i(x)+x $$如下图所示:与Inception v4的区别ResNeXt的分支的拓扑结构是相同的,Inception V4需要人工设计;ResNeXt是先进行 $1 \times 1$卷积然后执行单位加,Inception V4是先拼接再执行 $1 \times 1$ 卷积。2.1.7 ShuffleNet结构ShuffleNet v1 [论文]()作者通过分析Xception和ResNeXt模型,发现这两种结构通过卷积核拆分虽然计算复杂度均较原始卷积运算有所下降,然而拆分所产生的逐点卷积计算量却相当可观,成为了新的瓶颈。例如对于ResNeXt模型逐点卷积占据了93.4%的运算复杂度。可见,为了进一步提升模型的速度,就必须寻求更为高效的结构来取代逐点卷积。受ResNeXt的启发,作者提出使用分组逐点卷积(group pointwise convolution)来代替原来的结构。通过将卷积运算的输入限制在每个组内,模型的计算量取得了显著的下降。然而这样做也带来了明显的问题:在多层逐点卷积堆叠时,模型的信息流被分割在各个组内,组与组之间没有信息交换(如图 1(a)所示)。这将可能影响到模型的表示能力和识别精度。因此,在使用分组逐点卷积的同时,需要引入组间信息交换的机制。也就是说,对于第二层卷积而言,每个卷积核需要同时接收各组的特征作为输入,如上图(b)所示。作者指出,通过引入“通道重排”(channel shuffle,见上图(c))可以很方便地实现这一机制;并且由于通道重排操作是可导的,因此可以嵌在网络结构中实现端到端的学习。作者还观察到对于较小的网络(如ShuffleNet 0.25x),较大的分组会得到更好结果,认为更宽的通道对于小网络尤其重要。ShuffleNet v2 论文论文中提出了FLOPs不能作为衡量目标检测模型运行速度的标准,因为MAC(Memory access cost)也是影响模型运行速度的一大因素。由此,作者通过实验得出4个设计小模型的准则:卷积操作时,输入输出采用相同通道数可以降低MAC过多的组,会导致MAC增加分支数量过少,模型速度越快element-wise操作导致速度的消耗,远比FLOPs上体现的多。根据以上四点准则,作者在shuffleNet V1的基础上提出了修改得到了shuffleNet V2的基本快。2.1.8 GhostNet结构GhostNet 论文作者通过对比分析ResNet-50网络第一个残差组(Residual group)输出的特征图可视化结果,发现一些特征图高度相似(如Ghost一般,下图中的三组box内的图像对)。如果按照传统的思考方式,可能认为这些相似的特征图存在冗余,是多余信息,想办法避免产生这些高度相似的特征图。但本文思路清奇,推测CNN的强大特征提取能力和这些相似的特征图(Ghost对)正相关,不去刻意的避免产生这种Ghost对,而是尝试利用简单的线性操作来获得更多的Ghost对。常规卷积输入为$Y = w \times h \times c$,输出为$Y_1 = w_1 \times h_1 \times c_1$,运算量约为$w \times h \times c \times w_1 \times h_1 \times c_1$(忽略偏置计算)。Ghost ModuleGhost Module分为常规卷积、Ghost生成和特征图拼接三步1.首先用常规卷积得到本征特征图$Y'$(intrinsic feature maps),2.然后将本征特征图$Y'$每一个通道的特征图$y_i'$,用$\Phi_{i,j}$操作来产生Ghost特征图$y_{i,j}$对线性操作 $\Phi_{i,j}$的理解:论文中表示,可以探索仿射变换和小波变换等其他低成本的线性运算来构建Ghost模块。但是,卷积是当前硬件已经很好支持的高效运算,它可以涵盖许多广泛使用的线性运算,例如平滑、模糊等。 此外,线性运算 $\Phi_{i,j}$的滤波器的大小不一致将降低计算单元(例如CPU和GPU)的效率,所以论文中实验中让Ghost模块中的滤波器size取固定值,并利用Depthwise卷积实现 $\Phi_{i,j}$ ,以构建高效的深度神经网络。所以说,论文中使用的线性操作并不是常见的旋转、平移、仿射变换、小波变换等,而是用的Depthwise卷积。一种猜测可能是传统的线性操作效果没有Depthwise效果好,毕竟CNN可以自动调整filter的权值。3.最后将第一步得到的本征特征图和第二步得到的Ghost特征图拼接(identity连接)得到最终结果OutPut。当然也可以认为(论文中的思路),第2步中的$\Phi_{i,j}$中包含一个恒等映射,即将本征特征图直接输出,则不需用第三部,例如:对于$Y’$中的每一个特征图,对其进行$s$次映射,$s$次中包含一次恒等映射,其余$s-1$次为cheap operate来得到Ghost特征图,最终得到输出结果,这二者理论上完全一致。因此可以看出,Ghost Module和深度分离卷积是很类似的,不同之处在于先进行PointwiseConv,后进行DepthwiseConv,另外增加了DepthwiseConv的数量,包括一个恒定映射。2.1.9 SENet结构该结构与轻量化的关系不大,但是与提升整体的网络性能有关系,因此也放在这里一起进行介绍。SENet 论文SENet网络的创新点在于关注channel之间的关系,希望模型可以自动学习到不同channel特征的重要程度。论文通过显式地建模通道之间的相互依赖关系,自适应地重新校准通道的特征响应,从而设计了SE block如下图所示。论文的核心就是Squeeze和Excitation(论文牛的地方)两个操作。Squeeze(挤压)由于卷积只是在一个局部空间内进行操作,$U$(特征图)很难获得足够的信息来提取channel之间的关系,对于网络中前面的层这更严重,因为感受野比较小。为了,SENet提出Squeeze操作,将一个channel上整个空间特征编码为一个全局特征,采用global average pooling来实现(原则上也可以采用更复杂的聚合策略):$$ z_c = F_{sq}(u_c)=\frac{1}{H \times W}\sum^{H}_{i=1}\sum^{W}_{j=1}u_c(i,j),z \in R^C $$Excitation(激励)Sequeeze操作得到了全局描述特征,然后使用Excitation来抓取channel之间的关系。这个操作需要满足两个准则:首先要灵活,它要可以学习到各个channel之间的非线性关系;第二点是学习的关系不是互斥的,因为这里允许多channel特征,而不是one-hot形式。基于此,这里采用sigmoid形式的gating机制:$$ s =F_{ex}(z,W)=\sigma(g(z,W))=\sigma(W_2ReLU(W_1z)) $$为了降低模型复杂度以及提升泛化能力,这里采用包含两个全连接层的bottleneck结构,其中第一个FC层起到降维的作用,降维系数为r是个超参数,然后采用ReLU激活。最后的FC层恢复原始的维度。最后将学习到的各个channel的激活值(sigmoid激活,值0~1)乘以U上的原始特征(具体见下图SE模块在Inception和ResNet上的应用):$$ \tilde{x}c=Fscale(u_c,s_c)=s_c \cdot u_c $$整个操作可以看成学习到了各个channel的权重系数,从而使得模型对各个channel的特征更有辨别能力,这应该也算一种attention机制。SE模块在Inception和ResNet上的应用2.2 模型量化模型:特指卷积神经网络(用于提取图像/视频视觉特征)量化:将信号的连续取值(或者大量可能的离散取值)近似为有限多个(或较少的)离散值的过程。深度学习模型参数通常是32bit浮点型,我们能否使用16bit,8bit,甚至2bit来存储呢?答案是肯定的。这就是模型量化需要解决的问题。是什么阻碍了量化模型的落地?精度挑战大线性量化对分布的描述不精确8bit to 1bit:比特数越低,精度损失越大分类to检测to识别:任务越难,精度损失越大大模型to小模型:通常认为模型越小,精度损失越大Depthwise对量化不友好Merge BN, Fully Quantized软硬件支持程度不同硬件高效支持的低比特指令不一样不同软件库提供的量化方案/量化细节不一样不同软件库对于不同Layer的量化位置不一样速度能否变快不是所有的硬件上都提供高效的量化计算指令针对体系结构精细的优化不同结构优化方案不同系统&算法协同设计2.2.1 伪量化所谓伪量化是指在存储时使用低精度进行量化,但推理时会还原为正常高精度。为什么推理时不仍然使用低精度呢?这是因为一方面框架层有些算子只支持浮点运算,需要专门实现算子定点化才行。另一方面,高精度推理准确率相对高一些。伪量化可以实现模型压缩,但对模型加速没有多大效果。普通伪量化常见的做法是保存模型每一层时,利用低精度来保存每一个网络参数,同时保存拉伸比例scale(标度)和零值对应的浮点数zero_point(零点位置),量化公式如下:$$ Q(input,scale,zero\_point) = round(\frac{input}{scale}+zero\_point) $$推理阶段,再利用公式:$$ input = zero\_point + Q(input,scale,zero\_point) \times scale $$将网络参数还原为32bit浮点。eg:假设量化为qint8,设量化后的数Q为00011101,scale = 0.025 , zero_point = 0;最高位为0(符号位),所以是正数;后7位转换为10进制是29,所以Q代表的数为 :zero_point + Q scale = 0 + 29 0.025 = 0.725聚类与伪量化利用k-means等聚类算法,步骤如下:将大小相近的参数聚在一起,分为一类。每一类计算参数的平均值,作为它们量化后对应的值。每一类参数存储时,只存储它们的聚类索引。索引和真实值(也就是类内平均值)保存在另外一张表中推理时,利用索引和映射表,恢复为真实值。过程如下图所示,从上可见,当只需要4个类时,我们仅需要2bit就可以实现每个参数的存储了,压缩量达到16倍。推理时通过查找表恢复为浮点值,精度损失可控。2.2.2 定点化与伪量化不同的是,定点化在推理时,不需要还原为浮点数。这需要框架实现算子的定点化运算支持。目前NCNN、MNN、XNN等移动端AI框架中,均加入了定点化支持。2.2.3 其他角度分类二值化$$ Q_B(x)=sgn(x)=\begin{cases} +1,& if \ x \ge 0 \\ -1,& otherwise \end{cases} $$线性量化(对称、非对称、Ristretto)Quantize$$ x_{int} = round(\frac{x}{\Delta})+z \\ x_Q = clamp(0,N_{levels}-1,x_{int}) $$De-quantize$$ x_{float}=(x_Q-z)\Delta $$对数量化可将乘法转变为加法,加法转变为索引2.3 剪枝TODO参考资料理解分组卷积和深度可分离卷积如何降低参数量深度可分离卷积inception-v1,v2,v3,v4----论文笔记深度学习模型轻量化(上) ShuffleNet:一种极高效的移动端卷积神经网络 shuffleNet v1 v2笔记XceptionResNeXt详解ResNet系] 003 ResNeXt最后一届ImageNet冠军模型:SENetGhostNet论文解析:Ghost ModuleMobileNet系列轻量级神经网络“巡礼”(二)—— MobileNet,从V1到V3轻量化网络:MobileNet v3解析mobilenet系列之又一新成员---mobilenet-v3深度学习: 激活函数 (Activation Functions)轻量级网络:IGCV系列V1、V2、V3IGC系列:全分组卷积网络,分组卷积极致使用 | 轻量级网络pytorch量化中torch.quantize_per_tensor()函数参数详解深度学习模型轻量化(下) Szegedy C, Liu W, Jia Y, et al. Going deeper with convolutions[C]//Proceedings of the IEEE conference on computer vision and pattern recognition. 2015: 1-9.Ioffe S, Szegedy C. Batch normalization: Accelerating deep network training by reducing internal covariate shift[C]//International conference on machine learning. PMLR, 2015: 448-456.Szegedy C, Vanhoucke V, Ioffe S, et al. Rethinking the inception architecture for computer vision[C]//Proceedings of the IEEE conference on computer vision and pattern recognition. 2016: 2818-2826.Szegedy C, Ioffe S, Vanhoucke V, et al. Inception-v4, inception-resnet and the impact of residual connections on learning[C]//Thirty-first AAAI conference on artificial intelligence. 2017.模型量化了解一下?【商汤泰坦公开课】模型量化的那些事
2021年12月30日
662 阅读
0 评论
0 点赞
2021-12-30
Linux下出现bash: /bin/xx: 参数列表过长
1.现象描述当目录下文件过多时,执行类似如下命令会出现bash: /bin/xx: 参数列表过长的错误# 列出当前目的下的文件到txt ls * >>../all.txt # 删除符合某种条件的文件 rm *.txt # 对于remove、cp、move等同样适用。2.解决方案使用xargs+find配合进行解决。举例如下:# ls find . -name "*"|xargs ls >>../all.txt find . -type f -name "*"|xargs ls >>../all.txt # rm find . -name "*.log"|xargs rm -rf "*.log" # 对于remove、cp、move等同样适用。参考资料Linux那点事-xargs命令详解bash: /bin/ls: 参数列表过长bash: /bin/rm: 参数列表过长
2021年12月30日
1,025 阅读
1 评论
0 点赞
2021-12-23
Code-server:一款基于VScode的在线编辑器
1.介绍code-server是一款基于VScode的在线编辑器,主要用于在Linux服务器环境下,实现任何设备通过浏览器即可访问VScode, 进而实现在远程编程.GIthub官方文档:https://github.com/cdr/code-server2.安装使用一键脚本安装curl -fsSL https://code-server.dev/install.sh | sh修改配置文件vim ~/.config/code-server/config.yaml# 对以下内容自行进行修改 bind-addr: 0.0.0.0:8080 auth: password password: jupiter cert: false使用screen后台运行screen -S code-server code-server打开IP:8080输入密码测试参考资料https://github.com/coder/code-server
2021年12月23日
1,140 阅读
1 评论
0 点赞
2021-12-23
SSHFS:通过ssh实现挂载远程目录到本地
1.简介SSHFS(SSH Filesystem)是一个基于FUSE的文件系统客户端,用于通过SSH连接远程目录。SSHFS使用的是SFTP协议,它是SSH的一个子系统,在大多数SSH服务器上默认启用与其他网络文件系统(如NFS和Samba)相比,SSHFS的优势在于它不需要在服务器端进行任何额外的配置。要使用SSHFS,您只需要SSH访问远程服务器。2.安装ubuntusudo apt install sshfscenteOSsudo yum -y install sshfs3.使用3.1 命令格式挂载sshfs [user@]host:[dir] mountpoint [options] # 常用option -p PORT #指定端口取消挂载umount mountpoint3.2 示例sshfs root@192.168.0.105:/Shares /mnt # 挂载 umount /mnt # 取消挂载如果需要开机自动挂载,可以在/etc/fstab文件中添加挂载项(前提是需要设置无密码登录,不然开机不能挂载):echo 'root@192.168.0.105:/Shares /mnt fuse.sshfs defaults 0 0'>> /etc/fstab参考资料使用SSHFS文件系统远程挂载目录Ubuntu下使用sshfs挂载远程目录到本地
2021年12月23日
860 阅读
0 评论
0 点赞
2021-12-22
Next Terminal:在浏览器中管理你的服务器
1.介绍Next Terminal是使用Golang和React开发的一款HTML5的远程桌面网关,具有小巧、易安装、易使用、资源占用小的特点,支持RDP、SSH、VNC和Telnet协议的连接和管理。Next Terminal基于 Apache Guacamoleopen in new window 开发,使用到了guacd服务。目前支持的功能有:授权凭证管理资产管理(支持RDP、SSH、VNC、TELNET协议)指令管理批量执行命令在线会话管理(监控、强制断开)离线会话管理(查看录屏)双因素认证资产标签资产授权多用户&用户分组计划任务2.docker安装#docker安装Next Terminal docker run -d \ -p 8088:8088 \ --name next-terminal \ --restart always dushixiang/next-terminal:latest安装完毕后访问IP:8088,用户名为admin,密码为admin,登录后可在后台进行修改。参考资料使用Next Terminal在浏览器中管理你的服务器https://next-terminal.typesafe.cn/
2021年12月22日
1,036 阅读
0 评论
0 点赞
2021-12-22
h5ai:一款功能强大 php 文件目录列表程序
1.介绍h5ai是一款功能强大 php 文件目录列表程序,不需要数据库,支持在线预览文本、图片、音频、视频等。h5ai功能包括:文件排序,不同视图模式,本地化,面包屑,树视图,自定义页眉和页脚,文件过滤器和搜索,文件夹大小,自动刷新,打包下载,QR码,缩略图,文件预览。官网:https://larsjung.de/h5ai/github:https://github.com/lrsjng/h5ai2.宝塔安装2.1 php扩展安装与函数解禁在安装之前,我们需要在php中安装ImageMagick、fileinfo、exif扩展和解禁putenv函数。2.2 创建网站2.3 源码下载从官网或者github下载程序包,解压然后将_h5ai 上传到网站根目录: h5ai.inat.top/_h5ai.额,宝塔面板用户,直接就可以远程下载了。打开 http://h5ai.inat.top/_h5ai/public/index.php, 检查一下h5ai 是否可以访问. 同时,如果你的服务器有不兼容的话这里会显示。不过打开的时候,会要求你设置一个密码,当然留空也可以直接访问,登录之后,会有web环境检查的结果,如图:2.4 修改默认首页添加 /_h5ai/public/index.php 到默认的首页列表中添加好之后,我们就可以打开浏览器访问了,界面如下:3.给h5ai开启二维码、搜索、选择功能以下均在配置文件/www.xx.com/_h5ai/private/conf/options.json修改3.1 开启选择功能"select": { "enabled": false, "clickndrag": true, "checkboxes": true },将false修改为true,即:"select": { "enabled": true, "clickndrag": true, "checkboxes": true },该功能可方便我们进行批量下载。3.2开启搜索功能"search": { "enabled": false, "advanced": true, "debounceTime": 300, "ignorecase": true },将false修改为true,即:"search": { "enabled": true, "advanced": true, "debounceTime": 300, "ignorecase": true },开启后我们可以更快的找到文件了。3.3 开启二维码功能"info": { "enabled": false, "show": false, "qrcode": true, "qrFill": "#999", "qrBack": "#fff" },将false修改为true,即:"info": { "enabled": true, "show": true, "qrcode": true, "qrFill": "#999", "qrBack": "#fff" },开启二维码后,我们可以直接手机扫描二维码下载,很方便。参考资料h5ai-轻便又美观目录列表程序支持在线预览文本、图片、音频、视频等给h5ai开启二维码、搜索、选择功能
2021年12月22日
793 阅读
0 评论
0 点赞
2021-12-22
instantbox :几秒内启动一个干净的 Linux 系统
1.介绍instantbox一款非常实用的项目,它能够让你在几秒内启动一个主流的 Linux 系统,随起随用,支持 Ubuntu, CentOS, Arch Linux, Debian, Fedora 和 Alpine,通过 WebShell 访问,简单快捷,适合于演示、测试、体验等场合。喜欢尝试新玩意的青小蛙常常需要一台新的 Linux 系统进行测试,一则不能不影响现有系统,弄坏无压力,二则为了避免原环境对测试的影响。虽然有虚拟机、VPS,但新的 Linux系统还是需要一段时间才能创建完成,尤其如果 VPS 的话,你可能还需要支付几个小时的使用费用,而碰到 IP 不可用那种问题,纯属浪费时间。instantbox 提供了一个非常便捷的解决方案,它能够帮你在几秒钟内就启动一个干净的 Linux 发行版本,并且拥有多个版本,包括:Ubuntu:14.04、16.04、18.04、20.04 版本CentOS:6.10、7、8 版本Arch Linux:最新Debian:jessie、stretch、busterFedora:30、31Alpine:最新可以将 instantbox 理解为虚拟机中的临时虚拟机。2.如何安装 instantboxinstantbox 推荐使用 Docker 部署,直接使用官方提供的脚本即可:mkdir instantbox && cd $_ bash <(curl -sSL https://raw.githubusercontent.com/instantbox/instantbox/master/init.sh)或者下载 docker-compose.yml 文件,直接 docker-compose up -d 即可。3.如何使用 instantbox记得修改里面的端口,默认 8888。然后用浏览器打开 IP:8888,选择系统:选择配置,可选 CPU 核心数、内存、有效期然后,就会启动一个 WebShell 了,请尽情折腾,反正一天后就没了…注意由于其系统十分纯净,很多基础工具也可能需要安装才能使用,以 Ubuntu 为例,比如你要使用 ping,要先安装 apt install iputils-ping 才行。最后,关于权限,任何人知道你的 IP:端口 就能访问并使用,虽然不会对母机造成伤害,但可能会导致资源滥用,请注意保护。参考资料instantbox – 几秒内启动一个干净的 Linux 系统
2021年12月22日
707 阅读
0 评论
0 点赞
2021-12-21
nfs:Linux下挂载远程硬盘工具
本问以ubuntu为例,其他类似1.介绍NFS是Network File System的缩写,即网络文件系统。一种使用于分散式文件协定,功能是通过网络让不同的机器、不同的操作系统能够分享个人数据,让应用程序通过网络可以访问位于服务器磁盘中的数据。NFS在文件传送或信息传送的过过程中,依赖于RPC协议。RPC,远程过程调用(Remote Procedure Call),是使客户端能够执行其他系统中程序的一种机制。NFS本身是没有提供信息传输的协议和功能的,但NFS却能让我们通过网络进行资料的分享,就是因为NFS使用了RPC提供的传输协议,可以说NFS就是使用PRC的一个程序。NFS 存储 服务器主要用于用户上传的数据 ,图片 音频 、等信息 NFS服务端、RPC协议、客户端三者可以理解为房源、中介、租客之间的关系:2.应用场景现有两台Linux Server,需要把Linux01 下的硬盘/文件夹挂在到 Linux02 下;3.配置步骤-服务器端3.1 安装nfs-serversudo apt install nfs-server3.2 修改/etc/exports发布可供硬盘/文件夹sudo vim /etc/exports 然后输入: /datadrive02 *(insecure,rw,sync,no_root_squash,no_subtree_check) # /datadrive02 为需要挂载出去的硬盘 /datadrive02 :共享的目录 * :指定哪些用户可以访问 * 所有可以ping同该主机的用户 192.168.1.* 指定网段,在该网段中的用户可以挂载 192.168.1.12 只有该用户能挂载 (ro,sync,no_root_squash): 权限 ro : 只读 rw : 读写 sync : 同步 no_root_squash: 不降低root用户的权限3.3 重启 nfs-serversudo service nfs-server restart3.4 验证发布showmount -e + 主机IP(base) jupiter@dell:~$ showmount -e 127.0.0.1 Export list for 127.0.0.1: /data/project/音频剪辑/audio *4.挂载步骤-客户端4.1 安装 nfs-commonsudo apt install nfs-common4.2 挂载# sudo mount -t nfs 远程硬盘 挂载到本地后的名字(路径) sudo mount -t nfs 10.1.9.24:/data/project/音频剪辑/audio /audio4.3 验证(base) v100@v100:~$ df -h 文件系统 容量 已用 可用 已用% 挂载点 udev 16G 0 16G 0% /dev tmpfs 3.2G 124M 3.1G 4% /run /dev/sdb3 909G 166G 698G 20% / tmpfs 16G 59M 16G 1% /dev/shm tmpfs 5.0M 4.0K 5.0M 1% /run/lock tmpfs 16G 0 16G 0% /sys/fs/cgroup /dev/sdb1 975M 3.7M 971M 1% /boot/efi tmpfs 3.2G 28K 3.2G 1% /run/user/108 tmpfs 3.2G 96K 3.2G 1% /run/user/1000 /dev/sda1 3.7T 568G 3.1T 16% /data /dev/sdd2 3.7T 3.1T 630G 84% /4t /dev/sds1 466G 365G 102G 79% /drive /dev/sdu4 115G 39G 76G 34% /drive2 10.1.9.24:/data/project/音频剪辑/audio 458G 263G 172G 61% /audio参考资料Linux(Ubuntu)通过nfs挂载远程硬盘Ubuntu配置NFS的方法Linux下部署NFS服务 (* ̄︶ ̄)
2021年12月21日
964 阅读
0 评论
0 点赞
2021-12-21
Matomo:–免费开源的网站流量统计系统
1.简介Matomo(前身为Piwik)是一款很受欢迎的Google Analytics的开源替代工具。与Google Analytics不同,Matom是在你自己的服务器上托管的,你可以拥有你所有的数据。2.配置步骤2.1下载下载地址:https://builds.matomo.org/matomo.zip官网:https://matomo.org/安装文档:https://matomo.org/docs/installation/2.2 安装(宝塔环境,原生环境需要自行配置)解压然后在宝塔的控制台添加网站配置域名并将解压后的目录设置为网站根目录。然后我们用访问域名开始安装,不过首先可以把默认语言改成中文:下一步,web 环境检查,一般遇到的问题是 shell_exec 函数禁用,我们需要启用这个函数。在 php 管设置→禁用函数→删除 shell_exec 函数禁用:这时候重新检测 web 环境,我们看到已经全部通过。如图:接着下一步,需要填写数据库信息等等大家根据自己的数据库信息来填写吧:填写好之后,下一步,我们看到成功填写的信息,如图:继续下一步,这里需要设置管理员了,如图:下一步,需要设置需要被统计的网站,如图:接着下一步,设置被统计网站,如图:接着下一步,就设置完成了所有的需要设置的东东。三:基本设置我们登入到已安装好的 matomo 后台,后台和 wordpress 很像,已经极尽完善了,默认内置了 46 种插件,基本不需要安装什么插件了就可以使用了:如果我们需要安装插件,比如说安装 ip 地址位置插件,我们这样在插件管理中安装新插件:插件商城插件种类丰富,因为内置的是 GeoIP 如果你需要更换一个可以安装 IP2,如图:我们点击安装即可。当然你也可以直接在功能面板的左侧找到商城然后点击之后进去安装即可。参考资料Matomo前端埋点 matomo 详细安装配置 (一)Matomo – 免费开源的网站流量统计系统
2021年12月21日
855 阅读
0 评论
0 点赞
2021-12-20
ZeroTier:快速实现虚拟局域网VLAN/内网穿透
1.简介zerotier是一个软交换机,使用zerotier可以让多台内网机器组成一个局域网。官网: https://my.zerotier.comZeroTier 支持 Windows、macOS、Linux 三大主流平台,iOS、Android 两大移动平台,以及 QNAP(威连通)、Synology(群晖)、Western Digital MyCloud NAS(西部数据)三个 NAS 平台,还支持 LEDE 开源路由器项目。2.使用步骤2.1 注册 ZeroTier注册地址:https://my.zerotier.com/2.2创建私有局域网,获得 Network ID,然后修改Access Control进入https://my.zerotier.com/network点击Create创建网络点击进入已创建的网络,修改Access Control,默认是Certificate (Private Network),选择此模式表示每次在添加新的主机时,需要手动勾选是否允许连接,如果选择None (Public Network)模式,表示加入网络后自动分配IP并允许连接,从安全性来说建议使用默认选项Certificate (Private Network),方便性来看None (Public Network)更方便,不用每次加入网络后手动勾选。2.3客户端安装方式Linuxcurl -s https://install.zerotier.com | sudo bash如果要让他开机自启动,运行:sudo systemctl start zerotier-one.service sudo systemctl enable zerotier-one.serviceWindows或者macOS、Android、iOS等那么可以在 https://www.zerotier.com/download/ 下载zerotierr然后安装2.4连接,加入 Network IDsudo zerotier-cli join 83048a0632246d2c #填写自己的 Network ID2.5 验证ip a这个时候执行一下 ip a 你会发现多了一个叫做 ztuzethlza 或者类似名字的设备,还有IP地址,这就是zerotier组建的局域网的IP 地址zt3jnq5mka: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 2800 qdisc fq_codel state UNKNOWN group default qlen 1000 link/ether f6:4e:f8:49:0d:52 brd ff:ff:ff:ff:ff:ff inet 172.30.204.211/16 brd 172.30.255.255 scope global zt3jnq5mka valid_lft forever preferred_lft forever inet6 fe80::8e0:6ff:fe0e:1737/64 scope link valid_lft forever preferred_lft forever参考资料ZeroTier – 无配置,零基础「内网穿透」随时随地连回家/学校/办公室 -跨平台https://www.zerotier.com/download/zerotier简明教程无公网IP通过ZeroTier方便实现内网穿透(详细)
2021年12月20日
1,200 阅读
0 评论
0 点赞
2021-12-15
树莓派以及一些常见的硬件设备的浮点计算能力FLOPS
1.The GFLOPS/W of the various machines in the VMW Research Group#NameGFLOPS/WGFLOPSAverage PowerMax PowerIdle PowerarchvendortypeCores/ThreadsRAMOtherLinpack Settings1haswell-ep2.13 GFLOPS/W428 GFLOPS201 W298 W58.7 Wx86_64Intel 6/63/2hsw e5-2640v316 (32)80GB (N=80000, 16 threads, OpenBLAS)5Raspberry Pi-4B (4GB) 64-bit kernel/userspace2.02 GFLOPS/W13.5 GFLOPS6.66W7.30W2.56Waarch64ARMv8Cortex A7244GB (N=20000, 4 threads, OpenBLAS)3haswell/quadro (cpu only)1.68 GFLOPS/W181 GFLOPS107.9 W134.1 W29.3 Wx86_64Intel 6/60/3hsw i7-47904 (8)16GBQuadro K2200(N=40000, 4 threads, OpenBLAS)4broadwell macbookair1.64 GFLOPS/W47.7 GFLOPS29.1 W32.6 W10.0 Wx86_64Intel 6/61/4bdw i5-5250U2 (4)4GBmacbook-air(N=20000, 2 threads, OpenBLAS)5haswell desktop1.56 GFLOPS/W145 GFLOPS92.7 W126.6 W22.3 Wx86_64Intel 6/60/3hsw i7-47704 (8)4GB (N=20000, 4 threads, OpenBLAS)6Raspberry Pi-4B (1GB)1.50 GFLOPS/W9.92 GFLOPS6.6W7.9W2.9WARMARMv7/8Cortex A7241GB (N=9000, 4 threads, OpenBLAS)7haswell desktop (instrumented)1.47 GFLOPS/W115 GFLOPS80.6 W107 W25.9 Wx86_64Intel 6/60/3hsw i5-4570S4 (4)4GB (N=20000, 4 threads, OpenBLAS)8Raspberry Pi-4B (4GB)1.35 GFLOPS/W9.69 GFLOPS7.2W8.2W2.8WARMARMv7/8Cortex A7244GB (N=19000, 4 threads, OpenBLAS)9ivb mac-mini1.21 GFLOPS/W41.2 GFLOPS33.9 W35.8 W11.5 Wx86_64Intel 6/58/9ivb i5-3210M2 (4)4GB (N=20000, 2 threads, OpenBLAS)10jetson-tx11.20 GFLOPS/W16 GFLOPS13.4 W15.3 W2.1 WARMARMv8CortexA5744GBNVIDIA(N=20000, 4 thread, OpenBLAS)11Raspberry Pi-3A+1.19 GFLOPS/W5.00 GFLOPS4.1W7.6W1.4WARMARMv7/8Cortex A534512MB (N=5000, 4 threads, OpenBLAS)12raspberry pi 2B-v1.21.07 GFLOPS/W4.43 GFLOPS4.1W5.1W1.7WARMARMv7/8Cortex A5341GB2B-v1.2(N=8000, 4 threads, OpenBLAS)13ivb macbook-air1.02 GFLOPS/W34.5 GFLOPS34.0 W37.2 W13.8 Wx86_64Intel 6/58/9ivb i5-3427U2 (4)4GB (N=10000, 2 threads, OpenBLAS)14raspberry pi30.813 GFLOPS/W*3.62 GFLOPS4.3W4.8W1.8WARMARMv7/8Cortex A5341GB3 Model B(N=6000*, 4 threads, OpenBLAS)15fam17h-epyc0.795 GFLOPS/W109 GFLOPS137 W151 W67 Wx86_64AMD 23/1/2EPYC 72518 (16)16GB (N=40000, 8 threads, OpenBLAS)16raspberry pi 3B+0.73 GFLOPS/W5.3 GFLOPS7.3W9.4W2.6WARMARMv7/8Cortex A5341GB3B+(N=10000, 4 threads, OpenBLAS)17odroid-xu0.599 GFLOPS/W8.3 GFLOPS13.9 W18.4 W2.7 WARMARMv7Cortex A7/A154 Big 4 Little2GBExynos 5 Octa(N=12000, 4 threads, OpenBLAS)18fam15h-piledriver0.466 GFLOPS/W122 GFLOPS262 W335 W167 Wx86_64AMD 21/2/0Opteron 637616 (32)16GB (N=40000, 16 threads, OpenBLAS)19dragonboard0.450 GFLOPS/W2.10 GFLOPS4.7W5.7W2.4WARMARMv8Cortex-A5341GBSnapdragon 410c(N=8000, 4 threads, OpenBLAS)20haswell/quadro (GPU only)0.436 GFLOPS/W38.4 GFLOPS (Double)88.0 W121.1 W29.2 WNVIDIAQuadro K2200 4GB (N=40000, hpl-cuda)21raspberry pi20.432 GFLOPS/W1.47 GFLOPS3.4 W3.6 W1.8 WARMARMv7Cortex A741GBModel 2(N=10000, 4 threads, OpenBLAS)22fam15h-a100.432 GFLOPS/W54 GFLOPS125.6 W148.6 W28.2 Wx86_64AMD 21/19/1A10-6800B48GB (N=30000, 4 threads, OpenBLAS)23fam16h-a8-jaguar0.354 GFLOPS/W14.1 GFLOPS39.7 W43.6 W22.5 Wx86_64AMD 22/48/1A8-641044GB (N=10000, 4 threads, OpenBLAS)24core20.292 GFLOPS/W18.0 GFLOPS61.7 W67.9 W23.4 Wx86_64Intel 6/23/10Core2 P870024GB (N=15000, 2 threads, OpenBLAS)25chromebook0.277 GFLOPS/W3.0 GFLOPS10.7 W11.1 W5.9 WARMARMv7Cortex A1522GBExynos 5 Dual(N=10000, 2 threads, OpenBLAS)26fam10h-phenom0.277 GFLOPS/W40.3 GFLOPS145.4 W175.0 W69.5 Wx86_64AMD 16/4/3Phenom II X4 95542GB (N=15000, 4 threads, OpenBLAS)27raspberry pi-zero-w0.238 GFLOPS/W0.247 GFLOPS1.0 W1.1 W0.6 WARMARMv6BCM28351512MBModel Zero-W(N=4000, 1 thread, OpenBLAS)28raspberry pi-zero0.236 GFLOPS/W0.319 GFLOPS1.3 W1.4 W0.8 WARMARMv6BCM28351512MBModel Zero(N=5000, 1 thread, OpenBLAS)29raspberry pi-aplus0.223 GFLOPS/W0.218 GFLOPS1.0 W1.0 W0.8 WARMARMv6BCM28351256MBModel A+(N=4000, 1 thread, OpenBLAS)30cubieboard20.194 GFLOPS/W0.861 GFLOPS4.4W4.6W2.2WARMARMv7Cortex A721GBAllwinner A20(N=8000, 2 threads, OpenBLAS)31atom-cedarview desktop0.170 GFLOPS/W3.1 GFLOPS18.2 W18.5 W15.5 Wx86_64Intel 6/54/1Atom D25502 (4)4GB (N=10000, 2 threads, OpenBLAS)32pi-cluster0.166 GFLOPS/W15.5 GFLOPS93.1 W96.8 W71.3 WarmCortex A7Raspberry Pi 29624GB (N=48000, 96 threads, OpenBLAS)33pandaboard-es0.163 GFLOPS/W0.951 GFLOPS5.8 W6.5 W3.0 WARMARMv7Cortex A921GBES, OMAP4(N=4000, 2 threads, OpenBLAS)34atom-cedarview server0.149 GFLOPS/W2.6 GFLOPS22.1 W22.4 W18.6 Wx86_64Intel 6/54/9Atom S12602 (4)4GB (N=20000, 2 threads, OpenBLAS)35raspberry pi-bplus0.118 GFLOPS/W0.213 GFLOPS1.8 W1.9 W1.6 WARMARMv6BCM28351512MBModel B+(N=5000, 1 thread, OpenBLAS)36fam14h-bobcat0.106 GFLOPS/W2.76 GFLOPS26.1 W27.1 W14.8 Wx86_64AMD 20/2/0Bobcat22GBG-T56N(N=8000, 2 threads, OpenBLAS)37raspberry pi compute-module0.103 GFLOPS/W0.217 GFLOPS2.1W2.2W1.9WARMARMv6BCM28351512MBPi Compute Module(N=6000, 1 thread, OpenBLAS)38atom-eeepc0.086 GFLOPS/W1.37 GFLOPS15.9 W16.3 W10.2 Wx86Intel 6/28/2Atom N2701 (2)2GBeeepc 901(N=12000, 2 threads, OpenBLAS)39raspberry pi b0.073 GFLOPS/W0.213 GFLOPS2.9 W3.0 W2.7 WARMARMv6BCM28351512MBModel B(N=5000, 1 thread, OpenBLAS)40Pentium D0.064 GFLOPS/W10.3 GFLOPS160.7 W180.5 W77.2 Wx86_64Intel 15/6/5Pentium 4/D1 (2)1GB (N=8000, 2 threads, OpenBLAS)41beaglebone-black0.026 GFLOPS/W0.068 GFLOPS2.6 W2.8 W1.9 WARMARMv7Cortex A81512MBTI AM3(N=5000, 1 thread, OpenBLAS)42gumstix-overo0.015 GFLOPS/W0.041 GFLOPS2.7 W2.8 W2.0 WARMARMv7Cortex A81256MBTI OMAP3(N=4000, 1 thread, ATLAS)43beagleboard-xm0.014 GFLOPS/W0.054 GFLOPS4.0 W4.3 W3.2 WARMARMv7Cortex A81512MBTI DM3730(N=5000, 1 thread, OpenBLAS)44Pentium II0.005 GFLOPS/W0.238 GFLOPS48.3 W48.7 W31.2 Wx86Intel 6/5/2Pentium II1256MB (N=3000, 1 thread, OpenBLAS)45sparc0.003 GFLOPS/W0.456 GFLOPS140.7W146.8W136.9WSUNSPARCUltra1512MBTI Ultrasparc II(N=5000, 1 thread, OpenBLAS)46appleII6.65E-9 GFLOPS/W1.33E-7 GFLOPS20.1 W20.1 W20.1 WMOS65C02Apple IIe1128kplatinum(N=10, 1 thread, BASIC)?ELF Membership Card???? GFLOPS???ELFRCA1802 132kB???(??, 1 thread)?sandybridge-ep?85 GFLOPS???x86_64Intel 6/45/?snb12 (24)16GB (N=40000 12 threads, ATLAS)?trimslice???? GFLOPS???ARMARMv7Cortex A921GBTegra2????octane???? GFLOPS???MIPSSGIMIPS R12k1??????(??, 1 thread)?avr32???? GFLOPS???AVR32AVRAP70001??????(??, 1 thread)?gumstix-netstix???? GFLOPS???ARMARMv5Intel PXA255164MB???(??, 1 thread)?k6-2+???? GFLOPS???x86AMDK6-2+1?????(??, 1 thread)?486???? GFLOPS???x86Cyrix486120MB???(??, 1 thread)?g3-iBook???? GFLOPS???PPCAppleG31640MB???(??, 1 thread)?g4-powerBook???? GFLOPS???PPCAppleG412 GB???(??, 1 thread)?p4???? GFLOPS???x86IntelPentium 41768MB???(??, 1 thread)?core duo???? GFLOPS???x86IntelCore Duo22 GB???(??, 1 thread)2.The top 50 fastest computers in the Weaver Research Group#NameFLOPSarchvendortypeCores/ThreadsRAMOtherLinpack Settings1haswell-ep436 GFLOPSx86_64Intel 6/63/2hsw e5-2640v316 (32)80GB (N=100000, 16 threads, OpenBLAS)2power8195 GFLOPSppc64elIBM power88348-21c8 (64)32GB (N=40000, 8 threads, OpenBLAS)3broadwell-ep184 GFLOPSx86_64Intel 6/79/1bdw e5-2620v48 (16)32GB (N=50000, 8 threads, OpenBLAS)4haswell/quadro (CPU only)180 GFLOPSx86_64Intel 6/60/3hsw i7-47904 (8)16GBQuadro K2200(N=40000, 4 threads, OpenBLAS)!haswell/quadro (GPU only)38.4 GFLOPS (Double)NVIDIAQuadro K2200 4GB (N=40000, hpl-cuda)5skylake desktop161 GFLOPSx86_64Intel 6/94/3skl i7-67004 (8)8GB (N=30000, 4 threads, OpenBLAS)6haswell desktop145 GFLOPSx86_64Intel 6/60/3hsw i7-47704 (8)4GB (N=20000, 4 threads, OpenBLAS)7fam17h-epyc131 GFLOPSx86_64AMD 23/1/2EPYC 72518 (16)16GB (N=42000, 8 threads, OpenBLAS)8fam15h-piledriver117 GFLOPSx86_64AMD 21/2/0Opteron 637616 (32)16GB (N=40000, 16 threads, OpenBLAS)9haswell desktop (instrumented)115 GFLOPSx86_64Intel 6/60/3hsw i5-4570S4 (4)4GB (N=20000, 4 threads, OpenBLAS)10sandybridge-ep85 GFLOPSx86_64Intel 6/45/?snb12 (24)16GB (N=40000 12 threads, ATLAS)11elitebook77 GFLOPSx86_64AMD 23/24/1Ryzen 7-3700U4 (8)16GBZen+ elitebook laptop(N=20000, 4 threads, OpenBLAS)12broadwell NUC66 GFLOPSx86_64Intel 6/61/4Broadwell i7-5557U2 (4)8GBIntel NUC(N=20000, 2 threads, OpenBLAS)13fam15h-a1054 GFLOPSx86_64AMD 21/19/1A10-6800B48GB (N=30000, 4 threads, OpenBLAS)14broadwell MacBookAir51 GFLOPSx86_64Intel 6/61/4Broadwell i5-5250U2 (4)4GBmacbook-air(N=20000, 2 threads, OpenBLAS)15fam10h-phenom41 GFLOPSx86_64AMD 16/4/3Phenom II X4 95542GB (N=15000, 4 threads, OpenBLAS)16ivb-mac-mini40 GFLOPSx86_64Intel 6/58/9ivb i5-3210M2 (4)4GB (N=20000, 2 threads, OpenBLAS)17ivb-macbook-air36 GFLOPSx86_64Intel 6/58/9ivb i5-3427U2 (4)4GB (N=10000, 2 threads, OpenBLAS)18core218.4 GFLOPSx86_64Intel 6/23/10Core2 P870024GB (N=20000, 2 threads, OpenBLAS)19jetson-tx116.0 GFLOPSARMARMv8CortexA5744GBNVIDIA(N=20000, 4 thread, OpenBLAS)20pi-cluster15.4 GFLOPSarmCortex A7Raspberry Pi 29624GB (N=48000, OpenBLAS)21fam16h-a8-jaguar14.0 GFLOPSx86_64AMD 22/48/1A8-641044GB (N=10000, 4 threads, OpenBLAS)22Raspberry Pi-400 (4GB)13.8 GFLOPSARMARMv8Cortex A7244GB (N=12000, 4 threads, OpenBLAS)23Raspberry Pi-4B (4GB) (64-bit user/kernel)13.5 GFLOPSARM64 / aarch64ARMv8Cortex A7244GB (N=20000, 4 threads, OpenBLAS)24Pentium D11.8 GFLOPSx86_64Intel 15/6/5Pentium 4/D1 (2)1GB (N=10000, 2 threads, OpenBLAS)25Raspberry Pi-4B (1GB)10.3 GFLOPSARMARMv7/v8Cortex A7241GB (N=9000, 4 threads, OpenBLAS)26Raspberry Pi-4B (4GB)9.9 GFLOPSARMARMv7/v8Cortex A7244GB (N=19000, 4 threads, OpenBLAS)27odroid-xu8.3 GFLOPSARMARMv7Cortex A7/A154 Big 4 Little2GBExynos 5 Octa(N=12000, 4 threads, OpenBLAS)28Raspberry pi-3B+5.47 GFLOPSARMARMv7/8Cortex A5341GB3 Model B+(N=6000, 4 threads, OpenBLAS)29chromebook5.44 GFLOPSARMARMv7Cortex A1522GBExynos 5 Dual(N=10000, 2 threads, OpenBLAS)30Raspberry Pi-3A+4.93 GFLOPSARMARMv7/8Cortex A534512MB (N=5000, 4 threads, OpenBLAS)31Raspberry pi-2b-v1.24.39 GFLOPSARMARMv7/8Cortex A5341GB2 Model B v1.2(N=8000, 4 threads, OpenBLAS)32Raspberry pi-3b3.62 GFLOPSARMARMv7/8Cortex A5341GB3 Model B(N=8000*, 4 threads, OpenBLAS)33atom-cedarview server3.35 GFLOPSx86_64Intel 6/54/9Atom S12602 (4)4GB (N=20000, 2 threads, OpenBLAS)34atom-cedarview desktop2.97 GFLOPSx86_64Intel 6/54/1Atom D25502 (4)4GB (N=20000, 4 threads, OpenBLAS)35fam14h-bobcat2.76 GFLOPSx86_64AMD 20/2/0Bobcat22GBG-T56N(N=8000, 2 threads, OpenBLAS)36dragonboard2.22 GFLOPSARMARMv8Cortex-A5341GBSnapdragon 410c(N=8000, 4 threads, OpenBLAS)37Raspberry pi-2b1.47 GFLOPSARMARMv7Cortex A741GBModel 2(N=10000, 4 threads, OpenBLAS)38atom-eeepc1.36 GFLOPSx86Intel 6/28/2Atom N2701 (2)2GBeeepc 901(N=10000, 2 threads, OpenBLAS)39pandaboard-es0.915 GFLOPSARMARMv7Cortex A921GBES, OMAP4(N=5000 *, 2 threads, OpenBLAS)40cubieboard20.859 GFLOPSARMARMv7Cortex A721GBAllwinner A20(N=8000, 2 threads, OpenBLAS)41sparc0.423 GFLOPSSUNSPARCUltra1512MBTI Ultrasparc II(N=5000, 1 thread, OpenBLAS)42Raspberry pi-zero0.319 GFLOPSARMARMv6BCM28351512MBModel Zero(N=5000, 1 thread, OpenBLAS)43Raspberry pi-zero-w0.247 GFLOPSARMARMv6BCM28351512MBModel Zero W(N=4000, 1 thread, OpenBLAS)44Pentium II0.241 GFLOPSx86Intel 6/5/2Pentium II1256MB (N=4000, 1 thread, OpenBLAS)45Raspberry pi-aplus0.223 GFLOPSARMARMv6BCM28351256MBModel A+(N=4000, 1 thread, OpenBLAS)46Raspberry pi compute-module0.217 GFLOPSARMARMv6BCM28351512MBPi Compute Module(N=5000, 1 thread, OpenBLAS)47Raspberry pi-b0.213 GFLOPSARMARMv6BCM28351512MBModel B(N=5000, 1 thread, OpenBLAS)48Raspberry pi-bplus0.213 GFLOPSARMARMv6BCM28351512MBModel B+(N=5000, 1 thread, OpenBLAS)49beaglebone-black0.068 GFLOPSARMARMv7Cortex A81512MBTI AM3(N=5000, 1 thread, OpenBLAS)50beagleboard-xm0.054 GFLOPSARMARMv7Cortex A81512MBTI DM3730(N=5000, 1 thread, OpenBLAS)51gumstix-overo0.041 GFLOPSARMARMv7Cortex A81256MBTI OMAP3(N=4000, 1 thread, OpenBLAS)52appleII133 FLOPSMOS65C02Apple IIe1128kplatinum(N=10, 1 thread, BASIC)?ELF Membership Card??? GFLOPSELFRCA1802 132kB???(??, 1 thread)?trimslice??? GFLOPSARMARMv7Cortex A921GBTegra2????octane??? GFLOPSMIPSSGIMIPS R12k1??????(??, 1 thread)?avr32??? GFLOPSAVR32AVRAP70001??????(??, 1 thread)?gumstix-netstix??? GFLOPSARMARMv5Intel PXA255164MB???(??, 1 thread)?k6-2+??? GFLOPSx86AMDK6-2+1?????(??, 1 thread)?486??? GFLOPSx86Cyrix486120MB???(??, 1 thread)?g3-iBook??? GFLOPSPPCAppleG31640MB???(??, 1 thread)?g4-powerBook??? GFLOPSPPCAppleG412 GB???(??, 1 thread)?p4??? GFLOPSx86IntelPentium 41768MB???(??, 1 thread)?core duo??? GFLOPSx86IntelCore Duo22 GB???(??, 1 thread)参考资料http://web.eece.maine.edu/~vweaver/group/green_machines.htmlhttp://web.eece.maine.edu/~vweaver/group/machines.htmlhttps://github.com/deater/performance_results
2021年12月15日
2,454 阅读
0 评论
0 点赞
2021-12-13
设计模式学习笔记2:单例模式
1.介绍单例模式的定义就是确保某一个类只有一个实例,并且提供一个全局访问点。这种类型的设计模式属于创建型模式。单例模式具有典型的三个特点:只有一个实例。自我实例化。提供全局访问点。应用实例:1、一个班级只有一个班主任。2、Windows 是多进程多线程的,在操作一个文件的时候,就不可避免地出现多个进程或线程同时操作一个文件的现象,所以所有文件的处理必须通过唯一的实例来进行。3、一些设备管理器常常设计为单例模式,比如一个电脑有两台打印机,在输出的时候就要处理不能两台打印机打印同一个文件。优点:1、在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)。2、避免对资源的多重占用(比如写文件操作)。缺点:没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。使用场景:1、要求生产唯一序列号。2、WEB 中的计数器,不用每次刷新都在数据库里加一次,用单例先缓存起来。3、创建的一个对象需要消耗的资源过多,比如 I/O 与数据库的连接等。2.几种实现方式2.1 懒汉式,线程不安全是否 Lazy 初始化:是是否多线程安全:否描述:这种方式是最基本的实现方式,这种实现最大的问题就是不支持多线程。因为没有加锁 synchronized,所以严格意义上它并不算单例模式。这种方式 lazy loading 很明显,不要求线程安全,在多线程不能正常工作。// 懒汉式单例 public class LazyMan { // 1.私有化构造函数 private LazyMan(){} // 2.先定义单例对象但不实例化 private static LazyMan lazyMan; // 3.当发起调用的时候判断对象是否实例化,如果未实例化,则实例化再返回,否则直接返回 public static LazyMan getInstance(){ if (lazyMan==null){ lazyMan = new LazyMan(); } return lazyMan; } }2.2 懒汉式,线程安全是否 Lazy 初始化:是是否多线程安全:是描述:这种方式具备很好的 lazy loading,能够在多线程中很好的工作,但是,效率很低,99% 情况下不需要同步。优点:第一次调用才初始化,避免内存浪费。缺点:必须加锁 synchronized 才能保证单例,但加锁会影响效率。// 懒汉式单例 public class LazyMan { // 1.私有化构造函数 private LazyMan(){} // 2.先定义单例对象但不实例化 private static LazyMan lazyMan; // 3.当发起调用的时候判断对象是否实例化,如果未实例化,则实例化再返回,否则直接返回 public static synchronized LazyMan getInstance(){ if (lazyMan==null){ lazyMan = new LazyMan(); } return lazyMan; } }2.3 饿汉式是否 Lazy 初始化:否是否多线程安全:是描述:这种方式比较常用,但容易产生垃圾对象。优点:没有加锁,执行效率会提高。缺点:类加载时就初始化,浪费内存。// 饿汉式单例模式 public class Hungry { // 1.私有化构造函数 private Hungry(){} // 2.事先创建好对象 private final static Hungry HUNGRY = new Hungry(); // 3.当需要调用的单例对象的时候通过暴露的公有的方法进行调用 public static Hungry getInstance(){ return HUNGRY; } }2.4 双检锁/双重校验锁(DCL,即 double-checked locking)/DCL懒汉式单例是否 Lazy 初始化:是是否多线程安全:是实现难度:较复杂描述:这种方式采用双锁机制,安全且在多线程情况下能保持高性能。// 懒汉式单例 public class LazyMan { // 1.私有化构造函数 private LazyMan(){} // 2.先定义单例对象但不实例化 private volatile static LazyMan lazyMan; // 3.当发起调用的时候判断对象是否实例化,如果未实例化,则实例化再返回,否则直接返回 public static LazyMan getInstance(){ // 双重检测锁模式的懒汉式单例 DCL懒汉式 if (lazyMan==null){ synchronized (LazyMan.class){ if (lazyMan==null){ lazyMan = new LazyMan(); } } } return lazyMan; } }为什么要加volatilelazyMan = new LazyMan(); // 不是一个原子性操作创建对象的过程不是一个原子操作,分为以下3步:1.分配内存空间2.执行构造方法,初始化对象3.把这个对象指向这个空间在执行的过程中可能会发生指令重排的现象,即我们真实想要的执行顺序是1->2->3。但是可能真实的执行顺序是1->3->2。则当线程A以1->3->2的顺序执行到3时,线程B也调用了返回对象实例的方法,则给线程B可能拿到未创建完成的对象进行调用从而导致出错。2.5 登记式/静态内部类是否 Lazy 初始化:是是否多线程安全:是描述:这种方式能达到双检锁方式一样的功效,但实现更简单。对静态域使用延迟初始化,应使用这种方式而不是双检锁方式。这种方式只适用于静态域的情况,双检锁方式可在实例域需要延迟初始化时使用。public class Singleton { private static class SingletonHolder { private static final Singleton INSTANCE = new Singleton(); } private Singleton (){} public static final Singleton getInstance() { return SingletonHolder.INSTANCE; } }2.6 枚举描述:这种实现方式还没有被广泛采用,但这是实现单例模式的最佳方法。它更简洁,自动支持序列化机制,绝对防止多次实例化。这种方式是 Effective Java 作者 Josh Bloch 提倡的方式,它不仅能避免多线程同步问题,而且还自动支持序列化机制,防止反序列化重新创建新的对象,绝对防止多次实例化。public enum Singleton { INSTANCE; public void whateverMethod() { } }3.反射下的单例模式3.1 V1:在单例类已经实例化了对象的条件下使用反射破坏单例3.1.1 示例package single; import java.lang.reflect.Constructor; // 懒汉式单例 public class LazyMan { // 1.私有化构造函数 private LazyMan(){} // 2.先定义单例对象但不实例化 private volatile static LazyMan lazyMan; // 3.当发起调用的时候判断对象是否实例化,如果未实例化,则实例化再返回,否则直接返回 public static LazyMan getInstance(){ // 双重检测锁模式的懒汉式单例 DCL懒汉式 if (lazyMan==null){ synchronized (LazyMan.class){ if (lazyMan==null){ lazyMan = new LazyMan(); } } } return lazyMan; } public static void main(String[] args) throws Exception { LazyMan instance1 = LazyMan.getInstance(); // 获取空参构造器 Constructor<LazyMan> declareConstructor = LazyMan.class.getDeclaredConstructor(null); // 将空参构造器的Accessible设置为true declareConstructor.setAccessible(true); // 调用空参构造器实例化对象 LazyMan instance2 = declareConstructor.newInstance(); System.out.println(instance1); System.out.println(instance2); } } single.LazyMan@1b6d3586 single.LazyMan@4554617c3.1.2 防止措施通过在构造函数中加入一个同步代码块进行一次是否已经生成了该单例类对象的判断package single; import java.lang.reflect.Constructor; // 懒汉式单例 public class LazyMan { // 1.私有化构造函数 private LazyMan(){ synchronized (LazyMan.class){ if(lazyMan!=null){ throw new RuntimeException("不要试图使用反射破坏单例模式"); } } } // 2.先定义单例对象但不实例化 private volatile static LazyMan lazyMan; // 3.当发起调用的时候判断对象是否实例化,如果未实例化,则实例化再返回,否则直接返回 public static LazyMan getInstance(){ // 双重检测锁模式的懒汉式单例 DCL懒汉式 if (lazyMan==null){ synchronized (LazyMan.class){ if (lazyMan==null){ lazyMan = new LazyMan(); } } } return lazyMan; } public static void main(String[] args) throws Exception { LazyMan instance1 = LazyMan.getInstance(); // 获取空参构造器 Constructor<LazyMan> declareConstructor = LazyMan.class.getDeclaredConstructor(null); // 将空参构造器的Accessible设置为true declareConstructor.setAccessible(true); // 调用空参构造器实例化对象 LazyMan instance2 = declareConstructor.newInstance(); System.out.println(instance1); System.out.println(instance2); } }Exception in thread "main" java.lang.reflect.InvocationTargetException at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.lang.reflect.Constructor.newInstance(Constructor.java:423) at single.LazyMan.main(LazyMan.java:38) Caused by: java.lang.RuntimeException: 不要试图使用反射破坏单例模式 at single.LazyMan.<init>(LazyMan.java:11) ... 5 more3.2 V2:V1解决方案破解3.2.1 示例package single; import java.lang.reflect.Constructor; // 懒汉式单例 public class LazyMan { // 1.私有化构造函数 private LazyMan(){ synchronized (LazyMan.class){ if(lazyMan!=null){ throw new RuntimeException("不要试图使用反射破坏单例模式"); } } } // 2.先定义单例对象但不实例化 private volatile static LazyMan lazyMan; // 3.当发起调用的时候判断对象是否实例化,如果未实例化,则实例化再返回,否则直接返回 public static LazyMan getInstance(){ // 双重检测锁模式的懒汉式单例 DCL懒汉式 if (lazyMan==null){ synchronized (LazyMan.class){ if (lazyMan==null){ lazyMan = new LazyMan(); } } } return lazyMan; } public static void main(String[] args) throws Exception { // 获取空参构造器 Constructor<LazyMan> declareConstructor = LazyMan.class.getDeclaredConstructor(null); // 将空参构造器的Accessible设置为true declareConstructor.setAccessible(true); // 调用空参构造器实例化对象 LazyMan instance1 = declareConstructor.newInstance(); LazyMan instance2 = declareConstructor.newInstance(); System.out.println(instance1); System.out.println(instance2); } }3.2.2 防止措施--"红绿灯策略'',设置标志位package single; import java.lang.reflect.Constructor; // 懒汉式单例 public class LazyMan { private static boolean flag = false; // 1.私有化构造函数 private LazyMan(){ synchronized (LazyMan.class){ if(flag == false){ flag = true; }else{ throw new RuntimeException("不要试图使用反射破坏单例模式"); } } } // 2.先定义单例对象但不实例化 private volatile static LazyMan lazyMan; // 3.当发起调用的时候判断对象是否实例化,如果未实例化,则实例化再返回,否则直接返回 public static LazyMan getInstance(){ // 双重检测锁模式的懒汉式单例 DCL懒汉式 if (lazyMan==null){ synchronized (LazyMan.class){ if (lazyMan==null){ lazyMan = new LazyMan(); } } } return lazyMan; } public static void main(String[] args) throws Exception { // 获取空参构造器 Constructor<LazyMan> declareConstructor = LazyMan.class.getDeclaredConstructor(null); // 将空参构造器的Accessible设置为true declareConstructor.setAccessible(true); // 调用空参构造器实例化对象 LazyMan instance1 = declareConstructor.newInstance(); LazyMan instance2 = declareConstructor.newInstance(); System.out.println(instance1); System.out.println(instance2); } }3.3 V3:V2解决方案破解3.3.1 示例对字节码进行反编译获取到标志位,然后使用反射破解"红路灯"标志位package single; import java.lang.reflect.Constructor; import java.lang.reflect.Field; // 懒汉式单例 public class LazyMan { private static boolean flag = false; // 1.私有化构造函数 private LazyMan(){ synchronized (LazyMan.class){ if(flag == false){ flag = true; }else{ throw new RuntimeException("不要试图使用反射破坏单例模式"); } } } // 2.先定义单例对象但不实例化 private volatile static LazyMan lazyMan; // 3.当发起调用的时候判断对象是否实例化,如果未实例化,则实例化再返回,否则直接返回 public static LazyMan getInstance(){ // 双重检测锁模式的懒汉式单例 DCL懒汉式 if (lazyMan==null){ synchronized (LazyMan.class){ if (lazyMan==null){ lazyMan = new LazyMan(); } } } return lazyMan; } public static void main(String[] args) throws Exception { // 获取空参构造器 Constructor<LazyMan> declareConstructor = LazyMan.class.getDeclaredConstructor(null); // 将空参构造器的Accessible设置为true declareConstructor.setAccessible(true); // 调用空参构造器实例化对象 LazyMan instance1 = declareConstructor.newInstance(); // 获取"红绿灯标志位" Field flag = LazyMan.class.getDeclaredField("flag"); // 重置为"绿灯" flag.set(instance1,false); LazyMan instance2 = declareConstructor.newInstance(); System.out.println(instance1); System.out.println(instance2); } }single.LazyMan@4554617c single.LazyMan@74a144823.3.2 防止措施-使用枚举Enum实现单例模式import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; enum EnumSingle { INSTANCE; public EnumSingle getInstance(){ return INSTANCE; } } public class Test{ public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { EnumSingle instance1 = EnumSingle.INSTANCE; Constructor<EnumSingle> declaredConstructor = EnumSingle.class.getDeclaredConstructor(String.class,int.class); declaredConstructor.setAccessible(true); EnumSingle instance2 = declaredConstructor.newInstance(); System.out.println(instance1); System.out.println(instance2); } }Exception in thread "main" java.lang.IllegalArgumentException: Cannot reflectively create enum objects at java.lang.reflect.Constructor.newInstance(Constructor.java:417) at single.Test.main(EnumSingle.java:20)参考资料【狂神说Java】单例模式-23种设计模式系列单例模式Java中的双重检查锁(double checked locking) Java设计模式(一)之单例模式
2021年12月13日
624 阅读
0 评论
0 点赞
2021-12-10
设计模式学习笔记1:设计模式概述
1.什么是设计模式设计模式的概念最早是由 克⾥斯托佛·亚历⼭⼤ 在其著作 《建筑模式语⾔》 中⾸次提出的。 该书介绍了城市设计的 “语⾔”,提供了253个描述城镇、邻⾥、住宅、花园、房间及⻄部构造的模式, ⽽此类“语⾔” 的基本单元就是模式。后来, 埃⾥希·伽玛 、 约翰·弗利赛德斯 、 拉尔夫·约翰逊 和 理查德·赫尔姆 这四位大佬即GoF(Gang of Four,四人组/四人帮)接受了模式的概念。 1995 年, 他们出版了 《设计模式: 可复⽤⾯向对象软件的基础》⼀书,将设计模式的概念应⽤到程序开发领域中。该书 共收录了23种设计模式,从此树立了软件设计模式领域的里程碑,人称GoF设计模式。简单来说,设计模式(Design Pattern)是前辈们对代码开发经验的总结,是解决特定问题的一系列套路。它不是语法规定,而是一套用来提高代码可复用性、可维护性、可读性、稳健性以及安全性的解决方案。2.学习设计模式的意义设计模式的本质是面向对象设计原则的实际运用,是对类的封装性、继承性和多态性以及类的关联关系和组合关系的充分理解。正确使用设计模式具有以下优点:可以提高程序员的思维能力、编程能力和设计能力。使程序设计更加标准化、代码编制更加工程化,使软件开发效率大大提高,从而缩短软件的开发周期。使设计的代码可重用性高、可读性强、可靠性高、灵活性好、可维护性强。3.设计模式的基本要素4.GoF 23创建型模式:单例模式、工厂模式、抽象工厂模式、建造者模式、原型模式。结构型模式:适配器模式,桥接模式,装饰模式,组合模式,外观模式,享元模式,代理模式行为型模式:模板方法模式,命令模式,迭代器模式,观察者模式,中介者模式,备忘录模式,解释器模式,状态模式,策略模式,职责链模式,访问者模式。5.OOP七大原则开闭原则:对扩展开放,对修改关闭里氏替换原则:继承必须确保超类所拥有的性质在子类中仍然成立依赖倒置原则:要面向接口编程,不要面向实现编程。单一职责原则:控制类的粒度大小、将对象解耦、提高其内聚性。接口隔离原则:要为各个类建立它们需要的专用接口。迪米特法则:只与你的直接朋友交谈,不跟"陌生人"说话。合成复用原则:尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现。参考资料【狂神说Java】通俗易懂的23种设计模式教学(停更)设计模式简介
2021年12月10日
540 阅读
0 评论
0 点赞
1
...
13
14
15
...
24