MAE论文笔记+Pytroch实现

news/2024/5/5 1:47:19/文章来源:https://blog.csdn.net/qq_43428929/article/details/130036148

Masked Autoencoders Are Scalable Vision Learners, 2021

近期在梳理Transformer在CV领域的相关论文,落脚点在于如何去使用Pytroch实现如ViT和MAE等。通过阅读源码,发现不少论文的源码都直接调用timm来实现ViT。故在此需要简单介绍一下timm这个库中ViT相关部分。此外小破站上的李沐大神讲的贼棒,这里也顺带记录一下相关笔记。

文章目录

  • Masked Autoencoders Are Scalable Vision Learners, 2021
    • 一、timm库
    • 二、论文介绍
      • 1.动机
      • 2.方法
      • 3.实验
    • 三、Pytroch整体代码

一、timm库

可以参考这篇知乎文章视觉 Transformer 优秀开源工作:timm 库 vision transformer 代码解读,写的挺全的。

二、论文介绍

本篇论文提出了一个非对称自编码器架构(这里的非对称指的是Encoder和Decoder看到的东西即输入时不一样的),用来得到一个泛化能力比较强的特征提取器。进行自监督学习可以用来进行迁移学习。自编码器简单的说就是一个模型包含两个部分Encoder和Decoder,其中Encoder用来进行特征提取,Decoder用来进行还原图像。自编码器的任务是输入噪声或有损图片,输出重构好的图片,就是还原图片。通过训练,得到的特征提取器Encoder就有较强的特征提取能力,可以用来进行自监督学习。

什么叫自监督学习呢?简单的说就是构造一个pretext task,用来提高模型的特征提取能力。然后把得到的特征提取器迁移到下游任务。如自编码器的pretext task就是重构图像,如果输入和输出图像的差异越大,并且重构效果较好,往往得到的特征提取器性能也较好。我们可以把学习到的Encoder单独拿出来,后面根据特定的下游任务添加head。常见的使用方式为微调。微调往往能够加快收敛速度,甚至提高模型性能。

好了,介绍了这么多,接下来我们看一下本篇论文的动机+方法。

1.动机

在NLP领域,BERT(完成的任务类似于完形填空)等已经尝试使用masked autoencoding来产生具有较强泛化性能的大参数模型。但是目前CV领域相关工作较少。为了在CV领域使用masked autoencoding,作者从三个角度出发,分析了视觉和语言之间的区别:

  • 结构问题,CV领域主要使用CNN,这使得mask token和position embedding难以使用。但目前ViT的出现,弥补了这一差距。
  • 语言和视觉的信息密度不同。语言是人类产生的信号,具有高度的语义性和信息密集性。当训练一个模型来预测一个句子中只有几个缺失的单词时,这个任务似乎可以诱导复杂的语言理解。就是“完形填空”是一个比较复杂的任务,可以迫使神经网络学习到好的特征。相反,图像是具有严重空间冗余的自然信号,例如,一个丢失的块可以从对部分、对象和场景的高层理解很少的相邻块中恢复。为了克服这种差异并鼓励学习有用的特征,我们证明了一个简单的策略在计算机视觉中很好地工作:掩蔽很高比例的随机块。该策略在很大程度上减少了冗余,并创建了一个具有挑战性的自我监督任务,需要超越低级图像统计的整体理解。
  • 自动编码器的解码器将潜在的表示映射回输入,在重建文本和图像之间发挥着不同的作用。在视觉中,解码器重建像素,因此其输出的语义级别低于常见的识别任务。这与语言相反,解码器预测包含丰富语义信息的缺失单词。而在BERT中,解码器可以是一个MLP ,我们发现对于图像,解码器的设计在决定学习到的潜在表示的语义水平方面起着关键作用

基于上述三个发现,作者提出了本文的模型(细节方面作者通过大量的实验获得)。

在这里插入图片描述

2.方法

框架如上图所示,下面具体来说一下细节。

  • Masking: 我个人觉得Masking的主要目的是为了让模型能够学习到更强的特征,故输入的图像要和原图像相差很大,而且上面作者说了图像具有冗余性,故遮盖比例应该挺大的,如果遮盖比例比较小的话可能不需要进行训练直接插值就可能出来,且可能按规律裁剪效果不行。作者做了一些消融实验。这里的实验中的ft表示微调,lin表示linear probing即只调整线性层(类似于冻结网络)。
    在这里插入图片描述
    在这里插入图片描述

pytroch代码如下:

def random_masking(self, x, mask_ratio):"""Perform per-sample random masking by per-sample shuffling.Per-sample shuffling is done by argsort random noise.x: [N, L, D], sequence这里的x不是原始图像块,而是通过线性映射后的x,即embedding结果。batchsize=N,维度=D"""N, L, D = x.shape  # batch, length, dimlen_keep = int(L * (1 - mask_ratio))noise = torch.rand(N, L, device=x.device)  # noise in [0, 1]# sort noise for each sampleids_shuffle = torch.argsort(noise, dim=1)  # ascend: small is keep, large is removeids_restore = torch.argsort(ids_shuffle, dim=1) # 可以根据这个还原出排序过后的序列# keep the first subsetids_keep = ids_shuffle[:, :len_keep]x_masked = torch.gather(x, dim=1, index=ids_keep.unsqueeze(-1).repeat(1, 1, D)) # 这个函数是按照索引取值# generate the binary mask: 0 is keep, 1 is removemask = torch.ones([N, L], device=x.device)mask[:, :len_keep] = 0# unshuffle to get the binary maskmask = torch.gather(mask, dim=1, index=ids_restore)return x_masked, mask, ids_restore
  • MAE encoder: 这里的Encoder输入仅包含没有被mask掉的patch(这里作者也做了消融实验,发现只输入没有被mask掉的patch块较好)。如果训练好了,拿来做迁移学习,这个时候就没有mask操作了,输入的就是整张图片的patch块。网络结构采用的是ViT。对图像的输入处理和ViT类似,将图像块通过线性投影加位置编码输入到Encoder中。

代码如下,这里因为使用的是ViT,故需要添加class token:

from timm.models.vision_transformer import PatchEmbed, Block
from util.pos_embed import get_2d_sincos_pos_embeddef __init__(self, img_size=224, patch_size=16, in_chans=3,embed_dim=1024, depth=24, num_heads=16,decoder_embed_dim=512, decoder_depth=8, decoder_num_heads=16,mlp_ratio=4., norm_layer=nn.LayerNorm, norm_pix_loss=False):super().__init__()# --------------------------------------------------------------------------# MAE encoder specificsself.patch_embed = PatchEmbed(img_size, patch_size, in_chans, embed_dim)num_patches = self.patch_embed.num_patchesself.cls_token = nn.Parameter(torch.zeros(1, 1, embed_dim))self.pos_embed = nn.Parameter(torch.zeros(1, num_patches + 1, embed_dim), requires_grad=False)  # fixed sin-cos embedding,这是不可学习参数,下面还有一个赋值函数,太长了,没有列,最后会给一个总的代码。self.blocks = nn.ModuleList([Block(embed_dim, num_heads, mlp_ratio, qkv_bias=True, qk_scale=None, norm_layer=norm_layer)for i in range(depth)]) # Transformer blockself.norm = norm_layer(embed_dim)# --------------------------------------------------------------------------def forward_encoder(self, x, mask_ratio):# embed patchesx = self.patch_embed(x)# add pos embed w/o cls tokenx = x + self.pos_embed[:, 1:, :]# masking: length -> length * mask_ratiox, mask, ids_restore = self.random_masking(x, mask_ratio)# append cls tokencls_token = self.cls_token + self.pos_embed[:, :1, :]cls_tokens = cls_token.expand(x.shape[0], -1, -1)x = torch.cat((cls_tokens, x), dim=1)# apply Transformer blocksfor blk in self.blocks:x = blk(x)x = self.norm(x)return x, mask, ids_restore
  • MAE decoder: Decoder的输入包含Encoder的输出特征,以及之前的mask tokens,这里的mask tokens是共享可学习的参数。作者在这里给所有的输入添加了位置编码(positional embedding),结构依旧使用的是Transformer block。
        self.decoder_embed = nn.Linear(embed_dim, decoder_embed_dim, bias=True)self.mask_token = nn.Parameter(torch.zeros(1, 1, decoder_embed_dim))self.decoder_pos_embed = nn.Parameter(torch.zeros(1, num_patches + 1, decoder_embed_dim), requires_grad=False)  # fixed sin-cos embeddingself.decoder_blocks = nn.ModuleList([Block(decoder_embed_dim, decoder_num_heads, mlp_ratio, qkv_bias=True, qk_scale=None, norm_layer=norm_layer)for i in range(decoder_depth)])self.decoder_norm = norm_layer(decoder_embed_dim)self.decoder_pred = nn.Linear(decoder_embed_dim, patch_size**2 * in_chans, bias=True) # decoder to patchdef forward_decoder(self, x, ids_restore):# embed tokensx = self.decoder_embed(x) # 添加了一个线性层用来进行过渡# append mask tokens to sequencemask_tokens = self.mask_token.repeat(x.shape[0], ids_restore.shape[1] + 1 - x.shape[1], 1)x_ = torch.cat([x[:, 1:, :], mask_tokens], dim=1)  # no cls tokenx_ = torch.gather(x_, dim=1, index=ids_restore.unsqueeze(-1).repeat(1, 1, x.shape[2]))  # unshufflex = torch.cat([x[:, :1, :], x_], dim=1)  # append cls token# add pos embedx = x + self.decoder_pos_embed# apply Transformer blocksfor blk in self.decoder_blocks:x = blk(x)x = self.decoder_norm(x)# predictor projectionx = self.decoder_pred(x)# remove cls tokenx = x[:, 1:, :]return x
  • Reconstruction target: 为了重构出像素,解码器Decoder的最后一层是一个线性层。如果输入patch大小是16×16,那么线形层输出就是256维向量,通过reshape就可以还原了。损失函数使用的是MSE,这里的MSE只在mask掉的patch上做。

3.实验

作者先在ImageNet-1K上做自监督预训练,然后再在ImageNet-1K上做监督训练,监督训练方式有微调和linear probing(只允许改最后一层的线性输出层,类似冻结网络参数)。

这里ViT一开始未作改动是需要大规模数据去进行训练的,但后来有人发现添加强正则化会可以使得在相对较小的数据集上也可以训练出来。

在这里插入图片描述

  • 消融实验: 这里我比较感兴趣的就是数据增强这一部分,作者解释MAE对数据增强方法不是很敏感,但常见的对比学习方法却比较依赖于数据增强。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

上图的实验表示的是预训练的epoch数量对于结果的影响,可以看到当epochs=1600时效果还能不断提升。

  • 对比实验

在这里插入图片描述

在这里插入图片描述

  • 部分微调

这里作者想要知道到底微调多少层比较好。

在这里插入图片描述

  • 不同的下游任务性能

在这里插入图片描述

在这里插入图片描述

三、Pytroch整体代码

# Copyright (c) Meta Platforms, Inc. and affiliates.
# All rights reserved.# This source code is licensed under the license found in the
# LICENSE file in the root directory of this source tree.
# --------------------------------------------------------
# References:
# timm: https://github.com/rwightman/pytorch-image-models/tree/master/timm
# DeiT: https://github.com/facebookresearch/deit
# --------------------------------------------------------from functools import partialimport torch
import torch.nn as nnfrom timm.models.vision_transformer import PatchEmbed, Blockfrom util.pos_embed import get_2d_sincos_pos_embedclass MaskedAutoencoderViT(nn.Module):""" Masked Autoencoder with VisionTransformer backbone"""def __init__(self, img_size=224, patch_size=16, in_chans=3,embed_dim=1024, depth=24, num_heads=16,decoder_embed_dim=512, decoder_depth=8, decoder_num_heads=16,mlp_ratio=4., norm_layer=nn.LayerNorm, norm_pix_loss=False):super().__init__()# --------------------------------------------------------------------------# MAE encoder specificsself.patch_embed = PatchEmbed(img_size, patch_size, in_chans, embed_dim)num_patches = self.patch_embed.num_patchesself.cls_token = nn.Parameter(torch.zeros(1, 1, embed_dim))self.pos_embed = nn.Parameter(torch.zeros(1, num_patches + 1, embed_dim), requires_grad=False)  # fixed sin-cos embeddingself.blocks = nn.ModuleList([Block(embed_dim, num_heads, mlp_ratio, qkv_bias=True, qk_scale=None, norm_layer=norm_layer)for i in range(depth)])self.norm = norm_layer(embed_dim)# --------------------------------------------------------------------------# --------------------------------------------------------------------------# MAE decoder specificsself.decoder_embed = nn.Linear(embed_dim, decoder_embed_dim, bias=True)self.mask_token = nn.Parameter(torch.zeros(1, 1, decoder_embed_dim))self.decoder_pos_embed = nn.Parameter(torch.zeros(1, num_patches + 1, decoder_embed_dim), requires_grad=False)  # fixed sin-cos embeddingself.decoder_blocks = nn.ModuleList([Block(decoder_embed_dim, decoder_num_heads, mlp_ratio, qkv_bias=True, qk_scale=None, norm_layer=norm_layer)for i in range(decoder_depth)])self.decoder_norm = norm_layer(decoder_embed_dim)self.decoder_pred = nn.Linear(decoder_embed_dim, patch_size**2 * in_chans, bias=True) # decoder to patch# --------------------------------------------------------------------------self.norm_pix_loss = norm_pix_lossself.initialize_weights()def initialize_weights(self):# initialization# initialize (and freeze) pos_embed by sin-cos embeddingpos_embed = get_2d_sincos_pos_embed(self.pos_embed.shape[-1], int(self.patch_embed.num_patches**.5), cls_token=True)self.pos_embed.data.copy_(torch.from_numpy(pos_embed).float().unsqueeze(0))decoder_pos_embed = get_2d_sincos_pos_embed(self.decoder_pos_embed.shape[-1], int(self.patch_embed.num_patches**.5), cls_token=True)self.decoder_pos_embed.data.copy_(torch.from_numpy(decoder_pos_embed).float().unsqueeze(0))# initialize patch_embed like nn.Linear (instead of nn.Conv2d)w = self.patch_embed.proj.weight.datatorch.nn.init.xavier_uniform_(w.view([w.shape[0], -1]))# timm's trunc_normal_(std=.02) is effectively normal_(std=0.02) as cutoff is too big (2.)torch.nn.init.normal_(self.cls_token, std=.02)torch.nn.init.normal_(self.mask_token, std=.02)# initialize nn.Linear and nn.LayerNormself.apply(self._init_weights)def _init_weights(self, m):if isinstance(m, nn.Linear):# we use xavier_uniform following official JAX ViT:torch.nn.init.xavier_uniform_(m.weight)if isinstance(m, nn.Linear) and m.bias is not None:nn.init.constant_(m.bias, 0)elif isinstance(m, nn.LayerNorm):nn.init.constant_(m.bias, 0)nn.init.constant_(m.weight, 1.0)def patchify(self, imgs):"""imgs: (N, 3, H, W)x: (N, L, patch_size**2 *3)"""p = self.patch_embed.patch_size[0]assert imgs.shape[2] == imgs.shape[3] and imgs.shape[2] % p == 0h = w = imgs.shape[2] // px = imgs.reshape(shape=(imgs.shape[0], 3, h, p, w, p))x = torch.einsum('nchpwq->nhwpqc', x)x = x.reshape(shape=(imgs.shape[0], h * w, p**2 * 3))return xdef unpatchify(self, x):"""x: (N, L, patch_size**2 *3)imgs: (N, 3, H, W)"""p = self.patch_embed.patch_size[0]h = w = int(x.shape[1]**.5)assert h * w == x.shape[1]x = x.reshape(shape=(x.shape[0], h, w, p, p, 3))x = torch.einsum('nhwpqc->nchpwq', x)imgs = x.reshape(shape=(x.shape[0], 3, h * p, h * p))return imgsdef random_masking(self, x, mask_ratio):"""Perform per-sample random masking by per-sample shuffling.Per-sample shuffling is done by argsort random noise.x: [N, L, D], sequence"""N, L, D = x.shape  # batch, length, dimlen_keep = int(L * (1 - mask_ratio))noise = torch.rand(N, L, device=x.device)  # noise in [0, 1]# sort noise for each sampleids_shuffle = torch.argsort(noise, dim=1)  # ascend: small is keep, large is removeids_restore = torch.argsort(ids_shuffle, dim=1)# keep the first subsetids_keep = ids_shuffle[:, :len_keep]x_masked = torch.gather(x, dim=1, index=ids_keep.unsqueeze(-1).repeat(1, 1, D))# generate the binary mask: 0 is keep, 1 is removemask = torch.ones([N, L], device=x.device)mask[:, :len_keep] = 0# unshuffle to get the binary maskmask = torch.gather(mask, dim=1, index=ids_restore)return x_masked, mask, ids_restoredef forward_encoder(self, x, mask_ratio):# embed patchesx = self.patch_embed(x)# add pos embed w/o cls tokenx = x + self.pos_embed[:, 1:, :]# masking: length -> length * mask_ratiox, mask, ids_restore = self.random_masking(x, mask_ratio)# append cls tokencls_token = self.cls_token + self.pos_embed[:, :1, :]cls_tokens = cls_token.expand(x.shape[0], -1, -1)x = torch.cat((cls_tokens, x), dim=1)# apply Transformer blocksfor blk in self.blocks:x = blk(x)x = self.norm(x)return x, mask, ids_restoredef forward_decoder(self, x, ids_restore):# embed tokensx = self.decoder_embed(x)# append mask tokens to sequencemask_tokens = self.mask_token.repeat(x.shape[0], ids_restore.shape[1] + 1 - x.shape[1], 1)x_ = torch.cat([x[:, 1:, :], mask_tokens], dim=1)  # no cls tokenx_ = torch.gather(x_, dim=1, index=ids_restore.unsqueeze(-1).repeat(1, 1, x.shape[2]))  # unshufflex = torch.cat([x[:, :1, :], x_], dim=1)  # append cls token# add pos embedx = x + self.decoder_pos_embed# apply Transformer blocksfor blk in self.decoder_blocks:x = blk(x)x = self.decoder_norm(x)# predictor projectionx = self.decoder_pred(x)# remove cls tokenx = x[:, 1:, :]return xdef forward_loss(self, imgs, pred, mask):"""imgs: [N, 3, H, W]pred: [N, L, p*p*3]mask: [N, L], 0 is keep, 1 is remove, """target = self.patchify(imgs)if self.norm_pix_loss:mean = target.mean(dim=-1, keepdim=True)var = target.var(dim=-1, keepdim=True)target = (target - mean) / (var + 1.e-6)**.5loss = (pred - target) ** 2loss = loss.mean(dim=-1)  # [N, L], mean loss per patchloss = (loss * mask).sum() / mask.sum()  # mean loss on removed patchesreturn lossdef forward(self, imgs, mask_ratio=0.75):latent, mask, ids_restore = self.forward_encoder(imgs, mask_ratio)pred = self.forward_decoder(latent, ids_restore)  # [N, L, p*p*3]loss = self.forward_loss(imgs, pred, mask)return loss, pred, maskdef mae_vit_base_patch16_dec512d8b(**kwargs):model = MaskedAutoencoderViT(patch_size=16, embed_dim=768, depth=12, num_heads=12,decoder_embed_dim=512, decoder_depth=8, decoder_num_heads=16,mlp_ratio=4, norm_layer=partial(nn.LayerNorm, eps=1e-6), **kwargs)return modeldef mae_vit_large_patch16_dec512d8b(**kwargs):model = MaskedAutoencoderViT(patch_size=16, embed_dim=1024, depth=24, num_heads=16,decoder_embed_dim=512, decoder_depth=8, decoder_num_heads=16,mlp_ratio=4, norm_layer=partial(nn.LayerNorm, eps=1e-6), **kwargs)return modeldef mae_vit_huge_patch14_dec512d8b(**kwargs):model = MaskedAutoencoderViT(patch_size=14, embed_dim=1280, depth=32, num_heads=16,decoder_embed_dim=512, decoder_depth=8, decoder_num_heads=16,mlp_ratio=4, norm_layer=partial(nn.LayerNorm, eps=1e-6), **kwargs)return model# set recommended archs
mae_vit_base_patch16 = mae_vit_base_patch16_dec512d8b  # decoder: 512 dim, 8 blocks
mae_vit_large_patch16 = mae_vit_large_patch16_dec512d8b  # decoder: 512 dim, 8 blocks
mae_vit_huge_patch14 = mae_vit_huge_patch14_dec512d8b  # decoder: 512 dim, 8 blocks

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

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

相关文章

Linux 中的 /dev/random 和 /dev/urandom 是什么?

在Linux系统中,/dev/random和/dev/urandom是两个特殊的设备文件,用于生成随机数。在本文中,我们将深入探讨这两个设备文件的区别,以及它们在Linux系统中的作用。 /dev/random /dev/random是一个随机数生成器设备文件,…

windows10下编译zlib库

系列文章目录 文章目录系列文章目录前言一、问题原因二、准备具体操作编译zlib工程前言 我使用CMake编译zlib源码&#xff0c;出现警告&#xff1a;CMake Deprecation Warning at CMakeLists.txt:1 (cmake_minimum_required): Compatibility with CMake < 2.8.12 will be r…

五、基础初始化(init_sequence)

初始化序列数组 # < lib_arm\board.c > init_fnc_t *init_sequence[] { board_init, /* basic board dependent setup */ timer_init, /* initialize timer */ env_init, /* initialize environment */ init_baudrate, /* initialze baudrate settings */ serial_…

VUE3 学习笔记(七)动态样式 class 实现

目录 一、绑定 HTML class 1. 绑定对象 2. 绑定数组 3. 在组件上使用 二、绑定内联样式 1. 绑定对象 2. 绑定数组 3. 自动前缀 4. 样式多值 数据绑定的一个常见需求场景是操纵元素的 CSS class 列表和内联样式。因为 class 和 style 都是 attribute&#xff0c;我们可…

一道小学题,解答了我与学霸的差距

目录一、背景二、题目三、过程1.形式转换2.个位数相加只能向前进一位嘛&#xff1f;进两位可以吗&#xff1f;进三位呢&#xff1f;3.十位数上要填写的内容&#xff0c;可以是0嘛&#xff1f;你想到了吗&#xff1f;4.如何下意识的去做结构化&#xff1f;四、总结五、升华一、背…

讲一下dns过程:给一个网址www.google.com,dns服务器如何逐级解析的?

DNS 中的域名都是用句点来分隔的&#xff0c;比如 www.server.com&#xff0c;这里的句点代表了不同层次之间的界限。在域名中&#xff0c;越靠右的位置表示其层级越高。域名最后还有一个点&#xff0c;比如 www.server.com.&#xff0c;这个最后的一个点代表根域名。 根DNS服…

UDP套接字

大家好,又见面了,&#x1f389;&#x1f389;&#x1f389;&#x1f338;&#x1f338;&#x1f338; 今天为大家带来UDP套接字的相关知识 文章目录认识socketUDP和TCP认识UDPAPI有关方法基于UDP实现回显服务器UDP的方法基于UDP实现回显程序认识socket UDP和TCP 认识UDPAPI有…

腾讯空降测试工程师,绩效次次拿S,真是砂纸擦屁股,给我露了一手啊

​上周我们公司的绩效面谈全部结束了&#xff0c;每年到这个时间点就是打绩效的时候了&#xff0c;对于职场打工人来说绩效绝对是最重要的事情之一&#xff0c;原因也很简单&#xff1a;奖金、晋升、涨薪都和它有关系。 比如下面这个美团员工在脉脉上的自曝就很凄凉&#xff1…

多种方法解决VS在创建多个源文件后运行时出现的重定义错误:main已经在1.obj中定义

名人说&#xff1a;博学之&#xff0c;审问之&#xff0c;慎思之&#xff0c;明辨之&#xff0c;笃行之。——《中庸》 创作者&#xff1a;Code_流苏(CSDN) 本篇文章收录于&#xff1a;各类问题记录专栏 记录一、原因经过二、解决方法1️⃣方法一 注释2️⃣方法二 生成排除3️⃣…

学习Python的一些知识点记录

一、对象比较 Python中有两种对象比较方式&#xff1a; 值比较。使用比较符号&#xff08;、>、<等&#xff09;标识符比较。使用 is、not 关键字。标识符就是对象在内存中的有效地址&#xff0c;使用 id() 函数可以得到对象的标识符。二、None 对象 这是一个特殊对象…

【Python】数学 - 用 Python 自动化求解函数 f(x) 的值

目录 1、缘起 2、求以下函数的值 3、代码清单 3.1、求解 f(0)、f(1)、 f(​编辑)、f(​编辑) 3.2、求解 g(0)、g(1)、g(​编辑)、g(​编辑) 3.3、求解 h(0)、h(1)、h(​编辑)、h(​编辑) 4、总结 1、缘起 Python 是一种强大的编程语言&#xff0c;它具有广泛的应用领域。…

四、第二阶段

全局数据 声明 # < lib_arm\board.c > DECLARE_GLOBAL_DATA_PTR; 定义 # < include\asm\global_data.h > typedef struct global_data { bd_t *bd; unsigned long flags; unsigned long baudrate; unsigned long have_console; /* serial_init() was calle…

使用adb 命令删除手机预装app

1. 手机开启开发者选项&#xff0c;允许usb调试&#xff1b; 2.pc 安装adb&#xff0c; 1&#xff09;Windows版本&#xff1a;https://dl.google.com/android/repository/platform-tools-latest-windows.zip 2&#xff09;按键windowsr打开运行&#xff0c;输入sysdm.cpl&a…

Go 语言安装部署,两分钟让你写`上Hello World`(包含 goland 开发工具)

Go 语言安装部署&#xff0c;两分钟让你写上Hello World&#xff08;包含 goland 开发工具&#xff09; 第一步下载 Go 安装包 官网 https://golang.google.cn/dl/ 根据自己使用电脑平台选择安装版本 第二步 安装 GO 打开安装包直接点击next下一步 勾选协议&#xff0c;继…

10 kafka生产者发送消息的原理

1.发送原理&#xff1a; 在消息发送的过程中&#xff0c;涉及到了两个线程——main 线程和 Sender 线程。在 main 线程 中创建了一个双端队列 RecordAccumulator。main 线程将消息发送给 RecordAccumulator&#xff0c; Sender 线程不断从 RecordAccumulator 中拉取消息发送到…

CTFHub | 00截断

0x00 前言 CTFHub 专注网络安全、信息安全、白帽子技术的在线学习&#xff0c;实训平台。提供优质的赛事及学习服务&#xff0c;拥有完善的题目环境及配套 writeup &#xff0c;降低 CTF 学习入门门槛&#xff0c;快速帮助选手成长&#xff0c;跟随主流比赛潮流。 0x01 题目描述…

IDEA修改主题 设置背景图片

IDEA修改主题 设置背景图片 目录IDEA修改主题 设置背景图片1.修改IDEA默认主题2.修改IDEA背景图片2.1 打开设置界面2.2 下载插件很多小白在刚刚使用IDEA的时候还不是很熟练本文主要给大家提供一些使用的小技巧&#xff0c;希望能帮助到你1.修改IDEA默认主题 IDEA的默认主题是黑…

Jmeter 工具测试 websocket

WebSocket 是一种基于在单个 TCP 连接上进行全双工通信的协议&#xff0c;是从HTML5开始提供的一种浏览器与服务器之间进行全双工通讯的网络技术。相较于 HTTP 协议&#xff0c;WebSocket 协议实现了持久化网络通信&#xff0c;可以实现客户端和服务端的长连接&#xff0c;能够…

对Javascript中作用域的理解?

一、作用域 作用域&#xff0c;即变量&#xff08;变量作用域又称上下文&#xff09;和函数生效&#xff08;能被访问&#xff09;的区域或集合 换句话说&#xff0c;作用域决定了代码区块中变量和其他资源的可见性 举个例子 function myFunction() {let inVariable "…

C/C++中文参考手册离线最新版

最近又用回C/C刷题&#xff0c;回想上一年还在用Java&#xff0c;C/C才是世界上最好的语言&#xff08;纯属调侃&#xff09;。哼哼&#xff0c;不许反驳。 想分享我正在使用的C/C中文参考手册离线最新版给大家&#xff0c;需要的朋友们可以自行下载&#xff08;free的哦&#…