VGG16

1️⃣ VGG介绍

  Alexnet证明了神经网络变深是有效的,因此网络能不能更深更大?
  VGG(visual geometry group)是由牛津大学提出的使用“块思想”的网络,通过使用循环和子程序可以很容易地在任何现代深度学习框架的代码中实现这些重复的架构。
  VGG在2014ImageNet图像分类与定位挑战赛 ILSVRC-2014中取得在分类任务第二,定位任务第一的优异成绩。


2️⃣ 创新

  • LeNet(1995)
    • 2卷积+池化层
    • 2全连接层
  • AlexNet(2012)
    • 更大更深
    • ReLu,Dropout,数据增强
  • VGG(2014)
    • 相比Alexnet ,VGG使用了更小的卷积核,更深的网络结构,是一个利用小卷积核不断加深网络的一次尝试。

3️⃣ 网络结构

在这里插入图片描述
在这里插入图片描述
注意:上面这张图最后fc4096应该是fc1000,画错了

总的来说,VGG16由13个卷积层和3个全连接层组成,一共16层(池化层不算层数,因为不包含需要学习的权重和偏置)。

其中的13个卷积层可以分成5个VGG块:

  • 输入层:图片大小为3×224×224
  • 第1块:2个conv3-64组成(con3-64中3代表卷积核大小为3×3,64代表64个卷积核)
    • 第一个卷积:64个3×3卷积核,padding=1,stride=1
      输入:3×224×224
      输出:64×224×224
      再经过ReLu激活函数
    • 第二个卷积:64个3×3卷积核,padding=1,stride=1
      输入:64×224×224
      输出:64×224×224
      再经过ReLu激活函数
    • 最大池化:2×2,stride=2,padding=0
      输入:64×224×224
      输出:64×112×112
  • 第2块:2个conv3-128组成
    • 第一个卷积:128个3×3卷积核,padding=1,stride=1
      输入:64×112×112
      输出:128×112×112
      再经过ReLu激活函数
    • 第二个卷积:128个3×3卷积核,padding=1,stride=1
      输入:128×112×112
      输出:128×112×112
      再经过ReLu激活函数
    • 最大池化:2×2,stride=2,padding=0
      输入:128×112×112
      输出:128×56×56
  • 第3块:3个conv3-256组成
    • 第一个卷积:256个3×3卷积核,padding=1,stride=1
      输入:128×56×56
      输出:256×56×56
      再经过ReLu激活函数
    • 第二个卷积:256个3×3卷积核,padding=1,stride=1
      输入:256×56×56
      输出:256×56×56
      再经过ReLu激活函数
    • 第三个卷积:256个3×3卷积核,padding=1,stride=1
      输入:256×56×56
      输出:256×56×56
      再经过ReLu激活函数
    • 最大池化:2×2,stride=2,padding=0
      输入:256×56×56
      输出:256×28×28
  • 第4块:3个conv3-512组成
    • 第一个卷积:512个3×3卷积核,padding=1,stride=1
      输入:256×28×28
      输出:512×28×28
      再经过ReLu激活函数
    • 第二个卷积:512个3×3卷积核,padding=1,stride=1
      输入:512×28×28
      输出:512×28×28
      再经过ReLu激活函数
    • 第三个卷积:512个3×3卷积核,padding=1,stride=1
      输入:512×28×28
      输出:512×28×28
      再经过ReLu激活函数
    • 最大池化:2×2,stride=2,padding=0
      输入:512×28×28
      输出:512×14×14
  • 第5块:3个conv3-512组成
    • 第一个卷积:512个3×3卷积核,padding=1,stride=1
      输入:512×14×14
      输出:512×14×14
      再经过ReLu激活函数
    • 第二个卷积:512个3×3卷积核,padding=1,stride=1
      输入:512×14×14
      输出:512×14×14
      再经过ReLu激活函数
    • 第三个卷积:512个3×3卷积核,padding=1,stride=1
      输入:512×14×14
      输出:512×14×14
      再经过ReLu激活函数
    • 最大池化:2×2,stride=2,padding=0
      输入:512×14×14
      输出:512×7×7
  • 全连接层1:先通过nn.Flatten()将512×7×7展开到25088
    输入:25088
    输出:4096
    再经过ReLu激活函数
    再经过dropout=0.5
  • 全连接层2:
    输入:4096
    输出:4096
    再经过ReLu激活函数
    再经过dropout=0.5
  • 全连接层3
    输入:4096
    输出:1000
  • 最终输出层:
    输入:1000
    输出:2(将 1000 维映射到 2 维,二分类任务:猫和狗)

4️⃣ 代码

1. 分割数据,创建一个名为split_data.py的文件

需要数据集的话请私信我

import os
from shutil import copy
import random
from tqdm import tqdmdef mkfile(file):if not os.path.exists(file):os.makedirs(file)folder_path = "D:\\code\\AI_ladder\\2_VGG"# orig_data_path="D:\\code\\AI_ladder\\2_VGG\\data_origin"
orig_data_path = os.path.join(folder_path + '\\data_origin')
pet_class = [cla for cla in os.listdir(orig_data_path)]mkfile(folder_path + '\\data\\train')
mkfile(folder_path + '\\data\\val')for cla in pet_class:mkfile(folder_path + '\\data\\train\\' + cla)mkfile(folder_path + '\\data\\val\\' + cla)split_rate = 0.2# pet_class=['cat','dog']
for cla in pet_class:# D:\\code\\AI_ladder\\2_VGG\\data_origin\\cat\\# D:\\code\\AI_ladder\\2_VGG\\data_origin\\dog\\cla_path = orig_data_path + '\\' + cla + '\\'# cla_path路径下的所有图片文件名images = os.listdir(cla_path)# 统计数量num = len(images)eval_index = random.sample(images, k=int(num * split_rate))# enumerate(images),它会遍历 images 列表中的每个图片文件,同时生成一个 (index, image) 对,# 其中 index 是当前图片的索引,image 是当前图片的名称# 例如,假设 images = ['img1.jpg', 'img2.jpg', 'img3.jpg'],那么 enumerate(images) 将会生成:# (0, 'img1.jpg')# (1, 'img2.jpg')# (2, 'img3.jpg')# tqdm 接受一个迭代对象作为参数,并为这个迭代对象创建一个进度条显示。# 在这里,tqdm 接收 enumerate(images) 作为迭代对象# tqdm 会自动更新进度条,每次从 enumerate(images) 中获取一个新的 (index, image) 时,进度条会自动增加# total=len(images) 总共需要处理的图片数量,指定进度条的总长度loop = tqdm(enumerate(images),total=len(images))# 设置进度条的前缀描述信息loop.set_description(f'[{cla}]')for index, image in loop:# 验证集if image in eval_index:image_path = cla_path + imagenew_path = folder_path + '\\data\\val\\' + clacopy(image_path, new_path)# 训练集else:image_path = cla_path + imagenew_path = folder_path + '\\data\\train\\' + clacopy(image_path, new_path)print("\nprocessing done")

2.网络结构,创建一个名为network.py的文件

# 导入pytorch库
import torch
# 引入了神经网络模块nn
from torch import nn# 定义VGG类
class VGG(nn.Module):# conv_arch是VGG中每个块的配置参数,包含两部分:卷积层个数和输出通道数def __init__(self, conv_arch):super(VGG, self).__init__() self.conv_arch=conv_arch# 创建VGG块self.conv_blks = self.make_vgg_blocks(conv_arch)# 创建三个全连接层# 先nn.Flatten 将输入展平为一维张量,以便传入线性层# 全连接层1:第一个线性层的输入大小为 25088,输出大小为 4096,再经过ReLu和dropout# 全连接层2:第二个线性层的输入大小为 4096,输出大小为 4096,再经过ReLu和dropout# 全连接层3:第三个线性层的输入大小为 4096,输出大小为 10,# 二分类:最终输出层nn.Linear(1000, 2)self.fc = nn.Sequential(nn.Flatten(),nn.Linear(25088, 4096),nn.ReLU(),nn.Dropout(0.5),nn.Linear(4096, 4096),nn.ReLU(),nn.Dropout(0.5),nn.Linear(4096, 1000),nn.Linear(1000, 2))def make_vgg_blocks(self, conv_arch):# 定义了一个空列表blocks,用于存储生成的VGG块blocks = []# 输入通道维度in_channels = 3# 遍历 conv_arch# num_convs:卷积层个数# out_channels:输出通道数for (num_convs, out_channels) in conv_arch:# 创建VGG块blocks.append(self.vgg_block(num_convs, in_channels, out_channels))# 在块与块之间,下一个块的输入通道数等于上一个块的输出通道数in_channels = out_channelsreturn nn.Sequential(*blocks)# 静态方法,调用时不需要传递 self 参数,也就是说,这个方法不会直接访问实例属性@staticmethoddef vgg_block(num_convs, in_channels, out_channels):# 定义了一个空列表layers,用于存储VGG块中的所有层layers = []# 遍历 卷积层个数for _ in range(num_convs):# VGG中所有的卷积核的大小都是3×3,padding=1,stride=1layers.append(nn.Conv2d(in_channels=in_channels, out_channels=out_channels, kernel_size=3, padding=1))# 激活函数layers.append(nn.ReLU())# 在同一个块中,下一层卷积的输入通道数等于上一层输出的卷积通道数in_channels = out_channels# 最大池化,2×2,stride=2,padding=0layers.append(nn.MaxPool2d(kernel_size=2, stride=2))# 使用星号 * 对列表进行解包,将 layers 中的每个元素作为 nn.Sequential 的参数传递return nn.Sequential(*layers)def forward(self, x):feature = self.conv_blks(x)output = self.fc(feature)return outputdef register_hooks(model):# 定义钩子函数 hook:这是一个内部函数,它会被注册为模型每一层的钩子。# 在前向传播过程中,当每一层执行完毕时,这个钩子函数会被触发# module:表示当前被钩子的模块(层)。例如,它可以是卷积层、池化层、全连接层等。# input:是传入当前模块的输入张量,形状与输入数据的形状一致(通常是元组形式)。# output:是从当前模块得到的输出张量def hook(module, input, output):# 获取当前层的类名,例如 Conv2d、ReLU、MaxPool2d 等class_name = module.__class__.__name__# 打印当前层的类名和其输出张量的形状print(f"{class_name} Output Shape: {output.shape}")# 注册钩子函数for layer in model.modules():# 排除 nn.Sequential:nn.Sequential 是一个包含多个层的容器类,我们通常希望钩子直接注册到具体的层,而不是容器本身。# 排除 nn.ModuleList:nn.ModuleList 是另一种容器类,通常用于将多个模块按列表存储。# 排除顶级的模型类本身:检查 (layer == model) 以确保不会在整个模型对象上注册钩子if not isinstance(layer, nn.Sequential) and not isinstance(layer, nn.ModuleList) and not (layer == model):# 对于通过检查的每一个 layer,调用 register_forward_hook 方法,将之前定义的 hook 函数注册到该层上layer.register_forward_hook(hook)if __name__=='__main__':# conv_arch是VGG中每个块的配置参数,包含两部分:卷积层个数和输出通道数# VGG中的卷积包含padding,因此不改变高宽,卷积的作用是改变输出通道数# 对于VGG16来说,由5个块组成# 第1块:2个conv3-64组成(con3-64中3代表卷积核大小为3×3,64代表64个卷积核)# 第2块:2个conv3-128组成# 第3块:3个conv3-256组成# 第4块:3个conv3-512组成# 第5块:3个conv3-512组成conv_arch = ((2, 64), (2, 128), (3, 256), (3, 512), (3, 512))# 创建输入张量 X,其大小为 (1, 3, 224, 224),表示批次大小为 1、三通道、尺寸为 224x224X = torch.randn(size=(1, 3, 224, 224))# 实例化 VGG 模型 netnet = VGG(conv_arch)# 注册钩子以打印每层的输出尺寸register_hooks(net)# 进行一次前向传播,输出最终结果y = net(X)print('Final output:\t', y)

这里打印了每一层的输出大小,和前面通过公式计算得到的结果一致:

输入[1,3,224,224]
第一个VGG块
Conv2d Output Shape: torch.Size([1, 64, 224, 224])
ReLU Output Shape: torch.Size([1, 64, 224, 224])
Conv2d Output Shape: torch.Size([1, 64, 224, 224])
ReLU Output Shape: torch.Size([1, 64, 224, 224])
MaxPool2d Output Shape: torch.Size([1, 64, 112, 112])
第二个VGG块
Conv2d Output Shape: torch.Size([1, 128, 112, 112])
ReLU Output Shape: torch.Size([1, 128, 112, 112])
Conv2d Output Shape: torch.Size([1, 128, 112, 112])
ReLU Output Shape: torch.Size([1, 128, 112, 112])
MaxPool2d Output Shape: torch.Size([1, 128, 56, 56])
第三个VGG块
Conv2d Output Shape: torch.Size([1, 256, 56, 56])
ReLU Output Shape: torch.Size([1, 256, 56, 56])
Conv2d Output Shape: torch.Size([1, 256, 56, 56])
ReLU Output Shape: torch.Size([1, 256, 56, 56])
Conv2d Output Shape: torch.Size([1, 256, 56, 56])
ReLU Output Shape: torch.Size([1, 256, 56, 56])
MaxPool2d Output Shape: torch.Size([1, 256, 28, 28])
第四个VGG块
Conv2d Output Shape: torch.Size([1, 512, 28, 28])
ReLU Output Shape: torch.Size([1, 512, 28, 28])
Conv2d Output Shape: torch.Size([1, 512, 28, 28])
ReLU Output Shape: torch.Size([1, 512, 28, 28])
Conv2d Output Shape: torch.Size([1, 512, 28, 28])
ReLU Output Shape: torch.Size([1, 512, 28, 28])
MaxPool2d Output Shape: torch.Size([1, 512, 14, 14])
第五个VGG块
Conv2d Output Shape: torch.Size([1, 512, 14, 14])
ReLU Output Shape: torch.Size([1, 512, 14, 14])
Conv2d Output Shape: torch.Size([1, 512, 14, 14])
ReLU Output Shape: torch.Size([1, 512, 14, 14])
Conv2d Output Shape: torch.Size([1, 512, 14, 14])
ReLU Output Shape: torch.Size([1, 512, 14, 14])
MaxPool2d Output Shape: torch.Size([1, 512, 7, 7])
全连接层1
Flatten Output Shape: torch.Size([1, 25088])
Linear Output Shape: torch.Size([1, 4096])
ReLU Output Shape: torch.Size([1, 4096])
Dropout Output Shape: torch.Size([1, 4096])
全连接层2
Linear Output Shape: torch.Size([1, 4096])
ReLU Output Shape: torch.Size([1, 4096])
Dropout Output Shape: torch.Size([1, 4096])
全连接层3
Linear Output Shape: torch.Size([1, 1000])
最终输出层
Linear Output Shape: torch.Size([1, 2])

3.训练网络,创建一个名为train.py的文件

# 导入pytorch库
import torch
# 引入了神经网络模块nn
from torch import nn# 定义VGG类
class VGG(nn.Module):# conv_arch是VGG中每个块的配置参数,包含两部分:卷积层个数和输出通道数def __init__(self, conv_arch):super(VGG, self).__init__() self.conv_arch=conv_arch# 创建VGG块self.conv_blks = self.make_vgg_blocks(conv_arch)# 创建三个全连接层# 先nn.Flatten 将输入展平为一维张量,以便传入线性层# 全连接层1:第一个线性层的输入大小为 25088,输出大小为 4096,再经过ReLu和dropout# 全连接层2:第二个线性层的输入大小为 4096,输出大小为 4096,再经过ReLu和dropout# 全连接层3:第三个线性层的输入大小为 4096,输出大小为 10,# 二分类:最终输出层nn.Linear(1000, 2)self.fc = nn.Sequential(nn.Flatten(),nn.Linear(25088, 4096),nn.ReLU(),nn.Dropout(0.5),nn.Linear(4096, 4096),nn.ReLU(),nn.Dropout(0.5),nn.Linear(4096, 1000),nn.Linear(1000, 2))def make_vgg_blocks(self, conv_arch):# 定义了一个空列表blocks,用于存储生成的VGG块blocks = []# 输入通道维度in_channels = 3# 遍历 conv_arch# num_convs:卷积层个数# out_channels:输出通道数for (num_convs, out_channels) in conv_arch:# 创建VGG块blocks.append(self.vgg_block(num_convs, in_channels, out_channels))# 在块与块之间,下一个块的输入通道数等于上一个块的输出通道数in_channels = out_channelsreturn nn.Sequential(*blocks)# 静态方法,调用时不需要传递 self 参数,也就是说,这个方法不会直接访问实例属性@staticmethoddef vgg_block(num_convs, in_channels, out_channels):# 定义了一个空列表layers,用于存储VGG块中的所有层layers = []# 遍历 卷积层个数for _ in range(num_convs):# VGG中所有的卷积核的大小都是3×3,padding=1,stride=1layers.append(nn.Conv2d(in_channels=in_channels, out_channels=out_channels, kernel_size=3, padding=1))# 激活函数layers.append(nn.ReLU())# 在同一个块中,下一层卷积的输入通道数等于上一层输出的卷积通道数in_channels = out_channels# 最大池化,2×2,stride=2,padding=0layers.append(nn.MaxPool2d(kernel_size=2, stride=2))# 使用星号 * 对列表进行解包,将 layers 中的每个元素作为 nn.Sequential 的参数传递return nn.Sequential(*layers)def forward(self, x):feature = self.conv_blks(x)output = self.fc(feature)return outputdef register_hooks(model):# 定义钩子函数 hook:这是一个内部函数,它会被注册为模型每一层的钩子。# 在前向传播过程中,当每一层执行完毕时,这个钩子函数会被触发# module:表示当前被钩子的模块(层)。例如,它可以是卷积层、池化层、全连接层等。# input:是传入当前模块的输入张量,形状与输入数据的形状一致(通常是元组形式)。# output:是从当前模块得到的输出张量def hook(module, input, output):# 获取当前层的类名,例如 Conv2d、ReLU、MaxPool2d 等class_name = module.__class__.__name__# 打印当前层的类名和其输出张量的形状print(f"{class_name} Output Shape: {output.shape}")# 注册钩子函数for layer in model.modules():# 排除 nn.Sequential:nn.Sequential 是一个包含多个层的容器类,我们通常希望钩子直接注册到具体的层,而不是容器本身。# 排除 nn.ModuleList:nn.ModuleList 是另一种容器类,通常用于将多个模块按列表存储。# 排除顶级的模型类本身:检查 (layer == model) 以确保不会在整个模型对象上注册钩子if not isinstance(layer, nn.Sequential) and not isinstance(layer, nn.ModuleList) and not (layer == model):# 对于通过检查的每一个 layer,调用 register_forward_hook 方法,将之前定义的 hook 函数注册到该层上layer.register_forward_hook(hook)if __name__=='__main__':# conv_arch是VGG中每个块的配置参数,包含两部分:卷积层个数和输出通道数# VGG中的卷积包含padding,因此不改变高宽,卷积的作用是改变输出通道数# 对于VGG16来说,由5个块组成# 第1块:2个conv3-64组成(con3-64中3代表卷积核大小为3×3,64代表64个卷积核)# 第2块:2个conv3-128组成# 第3块:3个conv3-256组成# 第4块:3个conv3-512组成# 第5块:3个conv3-512组成conv_arch = ((2, 64), (2, 128), (3, 256), (3, 512), (3, 512))# 创建输入张量 X,其大小为 (1, 3, 224, 224),表示批次大小为 1、三通道、尺寸为 224x224X = torch.randn(size=(1, 3, 224, 224))# 实例化 VGG 模型 netnet = VGG(conv_arch)# 注册钩子以打印每层的输出尺寸register_hooks(net)# 进行一次前向传播,输出最终结果y = net(X)print('Final output:\t', y)

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Transformer多步时序预测:多变量输入,单变量输出

文章目录 Transformer类数据集类训练函数测试函数画图计算指标读取数据计时开始训练 数据集来源: https://github.com/zhouhaoyi/ETDataset import torch import torch.nn as nn import numpy as np import pandas as pd import math import time from sklearn.pre…

RabbitMq-队列交换机绑定关系优化为枚举注册

📚目录 📚简介:🚀比较💨通常注册🌈优化后注册 ✍️代码💫自动注册的关键代码 📚简介: 该项目介绍,rabbitMq消息中间件,对队列的注册,交换机的注册&#xff0c…

使用pyinstaller将python代码打包为exe程序

打包exe 对于不懂程序的人来说,可能有这样一个认识上的误区:只有能够直接打开的exe才是平常经常见到的程序,py文件不能算是程序。 在这种情况下,一些python的使用者可能非常苦恼:怎么才能够让我的程序,看…

博客搭建之路:hexo搜索引擎收录

文章目录 hexo搜索引擎收录以百度为例 hexo搜索引擎收录 hexo版本5.0.2 npm版本6.14.7 next版本7.8.0 写博客的目的肯定不是就只有自己能看到,想让更多的人看到就需要可以让搜索引擎来收录对应的文章。hexo支持生成站点地图sitemap 在hexo下的_config.yml中配置站点…

2-ZYNQ 折腾记录 -PMU

The AMD Zyng UltraScale MPSoC包括一个专用的用户可编程处理器,该平台测量单元(Platform Measurement Unit, PMU)处理器用于电源、错误管理和执行可选的软件测试库(Software Test Library, STL)用于功能安全应用。 PMU执行以下一组任务。启动前对系统的初始化。电…

Video-XL:面向小时级视频理解的超长视觉语言模型

在人工智能领域,视频理解一直是一个挑战性的任务,尤其是对于长时间视频内容的理解。现在,Video-XL的问世标志着我们在这一领域迈出了重要的一步。Video-XL是一个专为小时级视频理解设计的超长视觉语言模型,它能够处理超长视频序列…

BUUCTF之web篇

第一题 [极客大挑战 2019]EasySQL 打开靶机后可以看到这是一个登陆的页面 我们可以尝试两种方式登录 弱口令爆破(burpsuite) 通过SQL注入里的万能密码来跳过账户和密码验证的过程 这里就需要万能密码aor true # 在这里单引号的作用是结束用户名或者密码…

【Javaee】网络原理—http协议(一)

前言 本篇文章将详细介绍http协议,将介绍http抓包工具的下载与使用。 目录 一.http协议初识 1.概念 2.特点 1)版本 2)工作方式 二.http抓包工具 1.抓包是什么 2.抓包软件下载(Fiddler) 3.使用 三.http格式 …

04C++循环结构

//while 循环#include <iostream> using namespace std; int main() { int num0; while (num<10){ cout<<num<<endl; num; } return 0; } //do while语句 #include <iostream> using namespace std; int mai…

Appium中的api(一)

目录 1.基础python代码准备 1--参数的一些说明 2--python内所要编写的代码 解释 2.如何获取包名和界面名 1-api 2-完整代码 代码解释 3.如何关闭驱动连接 4.安装卸载app 1--卸载 2--安装 5.判断app是否安装 6.将应用放到后台在切换为前台的时间 7.UIAutomatorViewer的使用 1--找…

并联 高电压、高电流 放大器实现 2 倍输出电流模块±2A

1.1 并联输出电路设计注意事项 直接对两个功率运算放大器的输出进行硬接线并不是一种好的电气做法。如果两个运算放大器的输出直接连接在一起&#xff0c;则可能会导致不均匀的电流共享。这是因为其中的每个运算放大器都尝试强制施加略微不同的 Vout 电压&#xff0c;该电压取决…

vulnhub(16):sickos(两种打点方式)

端口 ip&#xff1a;192.168.72.154 nmap -Pn -p- 192.168.72.154 --min-rate 10000PORT STATE SERVICE 22 open ssh 3128 open http-proxy 8080 closed http-proxy web渗透方式一&#xff1a;web后台 正常访问80端口&#xff0c;是不开放的&#xff0c;我们需要配置…

高速定向广播声光预警系统赋能高速安全管控

近年来&#xff0c;高速重大交通事故屡见不鲜&#xff0c;安全管控一直是高速运营的重中之重。如何利用现代化技术和信息化手段&#xff0c;创新、智能、高效的压降交通事故的发生概率&#xff0c;优化交通安全管控质量&#xff0c;是近年来交管部门的主要工作&#xff0c;也是…

云原生Istio基础

一&#xff0e;Service Mesh 架构 Service Mesh&#xff08;服务网格&#xff09;是一种用于处理服务到服务通信的专用基础设施层。它的主要目的是将微服务之间复杂的通信和治理逻辑从微服务代码中分离出来&#xff0c;放到一个独立的层中进行管理。传统的微服务架构中&#x…

浅析Android View绘制过程中的Surface

前言 在《浅析Android中View的测量布局流程》中我们对VSYNC信号到达App进程之后开启的View布局过程进行了分析&#xff0c;经过对整个App界面的View树进行遍历完成了测量和布局&#xff0c;确定了View的大小以及在屏幕中所处的位置。但是&#xff0c;如果想让用户在屏幕上看到…

【十六进制数转十进制数 】

【十六进制数转十进制数 】 C语言版本C 版本Java版本Python版本 &#x1f490;The Begin&#x1f490;点点关注&#xff0c;收藏不迷路&#x1f490; 从键盘接收一个十六进制数&#xff0c;编程实现将其转换成十进制数。 输入 输入一个十六进制数 输出 输出一个十进制数 样…

GitHub 上的优质 Linux 开源项目,真滴硬核!

作为一名互联网人&#xff0c;提起 Linux 大家都不陌生&#xff0c;尤其是日常跟 Linux 操作系统打交道最多的&#xff0c;最熟悉不过了。互联网上关于 Linux 相关的教程和资料也非常的多&#xff0c;但是当你从中筛选出真正对自己有帮助的资料是需要花费很大精力与时间的。 G…

JVM基础(内存结构)

文章目录 内存结构JAVA堆方法区 &#xff08;Method Area&#xff09;运行时常量池&#xff08;Runtime Constant Pool&#xff09; 虚拟机栈 &#xff08;Java Virtual Machine Stack&#xff09;本地方法摘栈&#xff08;Native Method Stacks&#xff09;程序计数器&#xf…

交易的人生就是对未来不断的挑战!

在这个充满不确定性的市场中&#xff0c;我们每个人都渴望找到一条通往成功的路径。在Eagle Trader交易员中&#xff0c;有一位资深交易者&#xff0c;他不仅对交易有着不同寻常的执着和热爱&#xff0c;而且他的真诚见解和独到的交易哲学&#xff0c;可能会触动你的心弦。他的…

尚硅谷-react教程-求和案例-@redux-devtools/extension 开发者工具使用-笔记

## 7.求和案例_react-redux开发者工具的使用(1).npm install redux-devtools/extension(2).store中进行配置import { composeWithDevTools } from redux-devtools/extension;export default createStore(allReducer,composeWithDevTools(applyMiddleware(thunk))) src/redux/s…