昇思25天学习打卡营第4天|扩散模型

文章目录

      • 昇思MindSpore应用实践
        • 基于MindSpore的Diffusion扩散模型
          • 1、Diffusion Models 简介
          • 2、构建 Diffusion Model 的准备工作
          • 3、Attention 机制
          • 4、条件 U-Net
          • 5、Diffusion 正向过程
          • 6、Diffusion 反向过程
          • 7、Diffusion 模型训练
      • Reference

昇思MindSpore应用实践

本系列文章主要用于记录昇思25天学习打卡营的学习心得。

基于MindSpore的Diffusion扩散模型
1、Diffusion Models 简介

关于生成式模型,主要有GANs,VAEs,Flow Models,Diffusion Models,其中最常用的模型主要是生成对抗网络(GANs)和扩散模型(Diffusion Models),两种方法都能从潜在空间的随机噪声中采用并以对抗学习或反向扩散的方式,生成符合真实数据分布的结果,从而应用在各种生成式任务,如:图生图(风格转换)、文生图、语音转换、图像修复等。

在这里插入图片描述

采用GANs的生成方式训练和推理速度相比Diffusion通常较快,但容易产生模式崩塌。重复生成相同结果等问题。而扩散模型的训练更加稳定,且正向加噪过程和反向复原过程都可以通过严格的条件概率和贝叶斯公式推导证明,更具可解释性,缺点是由于需要多步的噪声去除过程,以计算出最符合原始数据分布的像素值从而生成高质量真实类别的图片,速度相比GANs慢。

2、构建 Diffusion Model 的准备工作

以 DDPM 生成图像为例,其前向过程就是给真实图片逐步添加噪声的过程,这个过程是固定的(Frozen),逐渐将高斯噪声添加到图像中,直到最终得到纯噪声。

扩散模型的正向与反向过程示意图:
在这里插入图片描述

实验部分,首先导入必要的mindspore接口:

import math
from functools import partial
%matplotlib inline
import matplotlib.pyplot as plt
from tqdm.auto import tqdm
import numpy as np
from multiprocessing import cpu_count
from download import download

import mindspore as ms
import mindspore.nn as nn
import mindspore.ops as ops
from mindspore import Tensor, Parameter
from mindspore import dtype as mstype
from mindspore.dataset.vision import Resize, Inter, CenterCrop, ToTensor, RandomHorizontalFlip, ToPIL
from mindspore.common.initializer import initializer
from mindspore.amp import DynamicLossScaler

ms.set_seed(0)

def linear_beta_schedule(timesteps):  # 正向扩散时间步设置
    beta_start = 0.0001
    beta_end = 0.02
    return np.linspace(beta_start, beta_end, timesteps).astype(np.float32)

mindspore官方文档中给出了构建一款Diffusion模型的帮助函数和类,用于神经网络的实现:

def rearrange(head, inputs):  # 调整张量分布
    b, hc, x, y = inputs.shape  # 输入形状
    c = hc // head            # 显然是用到了多头注意力机制,将特征维度分割为多个头处理
    return inputs.reshape((b, head, c, x * y))

def rsqrt(x):  # 计算逆平方根
    res = ops.sqrt(x)
    return ops.inv(res)

def randn_like(x, dtype=None):  # 生成与输入张量x形状一致的随机张量
    if dtype is None:
        dtype = x.dtype
    res = ops.standard_normal(x.shape).astype(dtype)
    return res

def randn(shape, dtype=None):  # 生成指定形状的随机张量
    if dtype is None:
        dtype = ms.float32
    res = ops.standard_normal(shape).astype(dtype)
    return res

def randint(low, high, size, dtype=ms.int32):  # 生成一个指定形状的整数随机数张量
    res = ops.uniform(size, Tensor(low, dtype), Tensor(high, dtype), dtype=dtype)
    return res

def exists(x):  # 判断某个变量是否被赋值
    return x is not None

def default(val, d):       # 用于设置默认值
    if exists(val):
        return val
    return d() if callable(d) else d

def _check_dtype(d1, d2):  # 检验数据类型是否兼容
    if ms.float32 in (d1, d2):
        return ms.float32
    if d1 == d2:
        return d1
    raise ValueError('dtype is not supported.')

class Residual(nn.Cell):  # 定义残差模块,源自何神CVPR2015的神来之笔
    def __init__(self, fn):
        super().__init__()
        self.fn = fn

    def construct(self, x, *args, **kwargs):
        return self.fn(x, *args, **kwargs) + x

def Upsample(dim):  # 上采样
    return nn.Conv2dTranspose(dim, dim, 4, 2, pad_mode="pad", padding=1)

def Downsample(dim):  # 下采样
    return nn.Conv2d(dim, dim, 4, 2, pad_mode="pad", padding=1)

# 位置向量,源自Transformer中的位置编码,让网络知道它在哪个特定时间步长(噪声水平)上运行
class SinusoidalPositionEmbeddings(nn.Cell):
    def __init__(self, dim):
        super().__init__()
        self.dim = dim
        half_dim = self.dim // 2
        emb = math.log(10000) / (half_dim - 1)
        emb = np.exp(np.arange(half_dim) * - emb)
        self.emb = Tensor(emb, ms.float32)

    def construct(self, x):
        emb = x[:, None] * self.emb[None, :]
        emb = ops.concat((ops.sin(emb), ops.cos(emb)), axis=-1)
        return emb

class Block(nn.Cell):
    def __init__(self, dim, dim_out, groups=1):
        super().__init__()
        self.proj = nn.Conv2d(dim, dim_out, 3, pad_mode="pad", padding=1)
        self.proj = c(dim, dim_out, 3, padding=1, pad_mode='pad')
        self.norm = nn.GroupNorm(groups, dim_out)
        self.act = nn.SiLU()

    def construct(self, x, scale_shift=None):
        x = self.proj(x)
        x = self.norm(x)

        if exists(scale_shift):
            scale, shift = scale_shift
            x = x * (scale + 1) + shift

        x = self.act(x)
        return x

# ResNet/ConvNeXT模块
class ConvNextBlock(nn.Cell):
    def __init__(self, dim, dim_out, *, time_emb_dim=None, mult=2, norm=True):
        super().__init__()
        self.mlp = (
            nn.SequentialCell(nn.GELU(), nn.Dense(time_emb_dim, dim))
            if exists(time_emb_dim)
            else None
        )
        
        self.ds_conv = nn.Conv2d(dim, dim, 7, padding=3, group=dim, pad_mode="pad")
        self.net = nn.SequentialCell(
            nn.GroupNorm(1, dim) if norm else nn.Identity(),
            nn.Conv2d(dim, dim_out * mult, 3, padding=1, pad_mode="pad"),
            nn.GELU(),
            nn.GroupNorm(1, dim_out * mult),
            nn.Conv2d(dim_out * mult, dim_out, 3, padding=1, pad_mode="pad"),
        )

        self.res_conv = nn.Conv2d(dim, dim_out, 1) if dim != dim_out else nn.Identity()

    def construct(self, x, time_emb=None):
        h = self.ds_conv(x)
        if exists(self.mlp) and exists(time_emb):
            assert exists(time_emb), "time embedding must be passed in"
            condition = self.mlp(time_emb)
            condition = condition.expand_dims(-1).expand_dims(-1)
            h = h + condition

        h = self.net(h)
        return h + self.res_conv(x)
3、Attention 机制

接下来是大名鼎鼎的Attention模块,其中使用了多头自注意力机制和线性注意力机制,其时间和内存要求在序列长度上线性缩放,而不是在常规注意力中缩放:

class Attention(nn.Cell):
    def __init__(self, dim, heads=4, dim_head=32):
        super().__init__()
        self.scale = dim_head ** -0.5
        self.heads = heads
        hidden_dim = dim_head * heads

        self.to_qkv = nn.Conv2d(dim, hidden_dim * 3, 1, pad_mode='valid', has_bias=False)
        self.to_out = nn.Conv2d(hidden_dim, dim, 1, pad_mode='valid', has_bias=True)
        self.map = ops.Map()
        self.partial = ops.Partial()

    def construct(self, x):
        b, _, h, w = x.shape
        qkv = self.to_qkv(x).chunk(3, 1)
        q, k, v = self.map(self.partial(rearrange, self.heads), qkv)

        q = q * self.scale

        # 'b h d i, b h d j -> b h i j'
        sim = ops.bmm(q.swapaxes(2, 3), k)
        attn = ops.softmax(sim, axis=-1)
        # 'b h i j, b h d j -> b h i d'
        out = ops.bmm(attn, v.swapaxes(2, 3))
        out = out.swapaxes(-1, -2).reshape((b, -1, h, w))

        return self.to_out(out)

class LayerNorm(nn.Cell):
    def __init__(self, dim):
        super().__init__()
        self.g = Parameter(initializer('ones', (1, dim, 1, 1)), name='g')

    def construct(self, x):
        eps = 1e-5
        var = x.var(1, keepdims=True)
        mean = x.mean(1, keep_dims=True)
        return (x - mean) * rsqrt((var + eps)) * self.g

class LinearAttention(nn.Cell):
    def __init__(self, dim, heads=4, dim_head=32):
        super().__init__()
        self.scale = dim_head ** -0.5
        self.heads = heads
        hidden_dim = dim_head * heads
        self.to_qkv = nn.Conv2d(dim, hidden_dim * 3, 1, pad_mode='valid', has_bias=False)

        self.to_out = nn.SequentialCell(
            nn.Conv2d(hidden_dim, dim, 1, pad_mode='valid', has_bias=True),
            LayerNorm(dim)
        )

        self.map = ops.Map()
        self.partial = ops.Partial()
        
        def construct(self, x):
        b, _, h, w = x.shape
        qkv = self.to_qkv(x).chunk(3, 1)
        q, k, v = self.map(self.partial(rearrange, self.heads), qkv)

        q = ops.softmax(q, -2)
        k = ops.softmax(k, -1)

        q = q * self.scale
        v = v / (h * w)

        # 'b h d n, b h e n -> b h d e'
        context = ops.bmm(k, v.swapaxes(2, 3))
        # 'b h d e, b h d n -> b h e n'
        out = ops.bmm(context.swapaxes(2, 3), q)

        out = out.reshape((b, -1, h, w))
        return self.to_out(out)

DDPM将U-Net的卷积和注意力层在注意力层之前进行组归一化:

class PreNorm(nn.Cell):
    def __init__(self, dim, fn):
        super().__init__()
        self.fn = fn
        self.norm = nn.GroupNorm(1, dim)

    def construct(self, x):
        x = self.norm(x)
        return self.fn(x)
4、条件 U-Net

相比于普通的编解码结构(Encoder-Decoder),U-Net在编码器和解码器之间引入了跳跃连接,极大地改善了梯度流:
在这里插入图片描述
基于mindspore的U-Net实现:
将先前预定义的位置编码、ResNet/ConvNeXT、Self-Attention和组归一化,用于定义现在的神经网络中。
网络获取了一批(batch_size, num_channels, height, width)形状的噪声图像和一批(batch_size, 1)形状的噪音水平作为输入,并返回(batch_size, num_channels, height, width)形状的张量。

网络构建过程如下:

  • 首先,将卷积层应用于噪声图像批上,并计算噪声水平的位置

  • 接下来,应用一系列下采样级。每个下采样阶段由2个ResNet/ConvNeXT块 + groupnorm + attention + 残差连接 + 一个下采样操作组成

  • 在网络的中间,再次应用ResNet或ConvNeXT块,并与attention交织

  • 接下来,应用一系列上采样级。每个上采样级由2个ResNet/ConvNeXT块+ groupnorm + attention + 残差连接 + 一个上采样操作组成

  • 最后,应用ResNet/ConvNeXT块,然后应用卷积层

最终,神经网络将层堆叠起来,并构成前向传播。

class Unet(nn.Cell):
    def __init__(
            self,
            dim,
            init_dim=None,
            out_dim=None,
            dim_mults=(1, 2, 4, 8),
            channels=3,
            with_time_emb=True,
            convnext_mult=2,
    ):
        super().__init__()

        self.channels = channels
        init_dim = default(init_dim, dim // 3 * 2)
        self.init_conv = nn.Conv2d(channels, init_dim, 7, padding=3, pad_mode="pad", has_bias=True)

        dims = [init_dim, *map(lambda m: dim * m, dim_mults)]
        in_out = list(zip(dims[:-1], dims[1:]))

        block_klass = partial(ConvNextBlock, mult=convnext_mult)

        if with_time_emb:
            time_dim = dim * 4
            self.time_mlp = nn.SequentialCell(
                SinusoidalPositionEmbeddings(dim), # 位置编码
                nn.Dense(dim, time_dim),
                nn.GELU(),
                nn.Dense(time_dim, time_dim),
            )
        else:
            time_dim = None
            self.time_mlp = None

        self.downs = nn.CellList([])
        self.ups = nn.CellList([])
        num_resolutions = len(in_out)

        for ind, (dim_in, dim_out) in enumerate(in_out):
            is_last = ind >= (num_resolutions - 1)

			# 下采样阶段
            self.downs.append(
                nn.CellList(
                    [
                        block_klass(dim_in, dim_out, time_emb_dim=time_dim),
                        block_klass(dim_out, dim_out, time_emb_dim=time_dim),
                        Residual(PreNorm(dim_out, LinearAttention(dim_out))),
                        Downsample(dim_out) if not is_last else nn.Identity(),
                    ]
                )
            )

        mid_dim = dims[-1]
        self.mid_block1 = block_klass(mid_dim, mid_dim, time_emb_dim=time_dim)
        self.mid_attn = Residual(PreNorm(mid_dim, Attention(mid_dim)))
        self.mid_block2 = block_klass(mid_dim, mid_dim, time_emb_dim=time_dim)

        for ind, (dim_in, dim_out) in enumerate(reversed(in_out[1:])):
            is_last = ind >= (num_resolutions - 1)

			# 上采样阶段
            self.ups.append(
                nn.CellList(
                    [
                        block_klass(dim_out * 2, dim_in, time_emb_dim=time_dim),
                        block_klass(dim_in, dim_in, time_emb_dim=time_dim),
                        Residual(PreNorm(dim_in, LinearAttention(dim_in))),
                        Upsample(dim_in) if not is_last else nn.Identity(),
                    ]
                )
            )

        out_dim = default(out_dim, channels)
        self.final_conv = nn.SequentialCell(
            block_klass(dim, dim), nn.Conv2d(dim, out_dim, 1)
        )

    def construct(self, x, time):  # 前向传播
        x = self.init_conv(x)
        t = self.time_mlp(time) if exists(self.time_mlp) else None
        h = []

        for block1, block2, attn, downsample in self.downs:  # 下采样阶段
            x = block1(x, t)
            x = block2(x, t)
            x = attn(x)
            h.append(x)

            x = downsample(x)

        x = self.mid_block1(x, t)
        x = self.mid_attn(x)
        x = self.mid_block2(x, t)

        len_h = len(h) - 1
        for block1, block2, attn, upsample in self.ups:  # 上采样阶段
            x = ops.concat((x, h[len_h]), 1)
            len_h -= 1
            x = block1(x, t)
            x = block2(x, t)
            x = attn(x)

            x = upsample(x)
        return self.final_conv(x)
5、Diffusion 正向过程

首先使用T=200的时间步长,定义噪声添加过程中需要的各种变量:

# 扩散200步
timesteps = 200

# 定义 beta schedule
betas = linear_beta_schedule(timesteps=timesteps)

# 定义 alphas
alphas = 1. - betas
alphas_cumprod = np.cumprod(alphas, axis=0)
alphas_cumprod_prev = np.pad(alphas_cumprod[:-1], (1, 0), constant_values=1)

sqrt_recip_alphas = Tensor(np.sqrt(1. / alphas))
sqrt_alphas_cumprod = Tensor(np.sqrt(alphas_cumprod))
sqrt_one_minus_alphas_cumprod = Tensor(np.sqrt(1. - alphas_cumprod))

# 计算 q(x_{t-1} | x_t, x_0)
posterior_variance = betas * (1. - alphas_cumprod_prev) / (1. - alphas_cumprod)

p2_loss_weight = (1 + alphas_cumprod / (1 - alphas_cumprod)) ** -0.
p2_loss_weight = Tensor(p2_loss_weight)

def extract(a, t, x_shape):
    b = t.shape[0]
    out = Tensor(a).gather(t, -1)
    return out.reshape(b, *((1,) * (len(x_shape) - 1)))

def q_sample(x_start, t, noise=None):  # 前向扩散过程
    if noise is None:
        noise = randn_like(x_start)
    return (extract(sqrt_alphas_cumprod, t, x_start.shape) * x_start +
            extract(sqrt_one_minus_alphas_cumprod, t, x_start.shape) * noise)

def p_losses(unet_model, x_start, t, noise=None):  # 模型的损失函数
    if noise is None:
        noise = randn_like(x_start)
    x_noisy = q_sample(x_start=x_start, t=t, noise=noise)
    predicted_noise = unet_model(x_noisy, t)

    loss = nn.SmoothL1Loss()(noise, predicted_noise)# todo
    loss = loss.reshape(loss.shape[0], -1)
    loss = loss * extract(p2_loss_weight, t, loss.shape)
    return loss.mean()
6、Diffusion 反向过程

在这里插入图片描述
可以通过上述过程,即Diffusion Models生成高质量的结果,如下图中的人脸图像均是生成出来的,并不是现实中实际的人脸:
在这里插入图片描述

7、Diffusion 模型训练

以Fashion_Mnist为例的 Diffusion 模型训练过程如下,具体完整代码可登录昇思大模型平台扩散模型的Jupyter notebook进行尝试,打印log如下:

# 定义动态学习率
lr = nn.cosine_decay_lr(min_lr=1e-7, max_lr=1e-4, total_step=10*3750, step_per_epoch=3750, decay_epoch=10)

# 定义 Unet模型
unet_model = Unet(
    dim=image_size,
    channels=channels,
    dim_mults=(1, 2, 4,)
)

name_list = []
for (name, par) in list(unet_model.parameters_and_names()):
    name_list.append(name)
i = 0
for item in list(unet_model.trainable_params()):
    item.name = name_list[i]
    i += 1

# 定义优化器
optimizer = nn.Adam(unet_model.trainable_params(), learning_rate=lr)
loss_scaler = DynamicLossScaler(65536, 2, 1000)

# 定义前向过程
def forward_fn(data, t, noise=None):
    loss = p_losses(unet_model, data, t, noise)
    return loss

# 计算梯度
grad_fn = ms.value_and_grad(forward_fn, None, optimizer.parameters, has_aux=False)

# 梯度更新
def train_step(data, t, noise):
    loss, grads = grad_fn(data, t, noise)
    optimizer(grads)
    return loss

import time

epochs = 10

for epoch in range(epochs):
    begin_time = time.time()
    for step, batch in enumerate(dataset.create_tuple_iterator()):
        unet_model.set_train()
        batch_size = batch[0].shape[0]
        t = randint(0, timesteps, (batch_size,), dtype=ms.int32)
        noise = randn_like(batch[0])
        loss = train_step(batch[0], t, noise)

        if step % 500 == 0:
            print(" epoch: ", epoch, " step: ", step, " Loss: ", loss)
    end_time = time.time()
    times = end_time - begin_time
    print("training time:", times, "s")
    # 展示随机采样效果
    unet_model.set_train(False)
    samples = sample(unet_model, image_size=image_size, batch_size=64, channels=channels)
    plt.imshow(samples[-1][5].reshape(image_size, image_size, channels), cmap="gray")
print("Training Success!")

由于时间原因,只训练几个Epoch的可视化效果不是很好,loss未进入收敛状态。Fashion_Mnist单张输入只是28x28x1的shape,可以感受到diffusion的训练速度要比GAN慢了很多。如果时间充足,可以用Asend910尝试多跑几个epoch;
在这里插入图片描述
在这里插入图片描述

Reference

综述 - 扩散模型 - Diffusion Models
MindSpore官方文档-Diffusion扩散模型
annotated-diffusion
由浅入深了解Diffusion Model

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

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

相关文章

掌握Python编程的深层技能

一、Python基础语法、变量、列表、字典等运用 1.运行python程序的两种方式 1.交互式即时得到程序的运行结果 2.脚本方式把程序写到文件里(约定俗称文件名后缀为.py),然后用python解释器解释执行其中的内容2.python程序运行的三个步骤 python3.8 C:\a\b\c.py 1.先启动python3…

什么是产线工控安全,如何保障产线设备的安全

什么是产线工控安全? 工控,指的是工业自动化控制,主要利用电子电气、机械、软件组合实现。即是工业控制系统,或者是工厂自动化控制。产线工控安全指的是工业控制系统的数据、网络和系统安全。随着工业信息化的迅猛发展&#xff0…

【Lua】第一篇:在Linux系统中安装搭建lua5.4.1环境

文章目录 一. 远程下载安装包二. 解压安装包三. 编译安装Lua环境 一. 远程下载安装包 输入以下命令即可在当前目录下,远程下载安装包lua-5.4.1.tar.gz: wget http://www.lua.org/ftp/lua-5.4.1.tar.gzPS:其他版本的安装包如下,可…

鸿蒙项目实战-月木学途:1.编写首页,包括搜索栏、轮播图、宫格

效果展示 搜索栏制作 相关知识回顾 输入框组件TextInput 单行输入框类型.type(InputType.Normal)//基本输入框.type(InputType.Password)//密码.type(InputType.Email)//邮箱.type(InputType.Number)//数字.type(InputType.PhoneNumber)//电话号.type(InputType.Normal).type…

【折腾手机】一加6T刷机postmarketOS经历和体验

写在前面 到目前为止,我已经花了非常多的时间去学习和了解x86架构和RISC-V架构,对它们的指令集编程、指令格式的设计、编译套件的使用都亲自去体会和实践过,学到了很多的东西。但是对于离我们最近的arm架构却了解甚少。为什么说离我们最近呢…

Python | Leetcode Python题解之第199题二叉树的右视图

题目: 题解: class Solution:def rightSideView(self, root: TreeNode) -> List[int]:rightmost_value_at_depth dict() # 深度为索引,存放节点的值max_depth -1stack [(root, 0)]while stack:node, depth stack.pop()if node is not…

15 个适用于企业的生成式 AI 用例

作者:来自 Elastic Jennifer Klinger 关于生成式人工智能及其能做什么(和不能做什么)有很多讨论。生成式人工智能(例如大型语言模型 - LLMs)利用从大量训练数据中学习到的模式和结构来创建原创内容,而无需存…

weiyang**2.部署

一、官方文档 一键部署可以在 同机 快速搭建WeBASE管理台环境,方便用户快速体验WeBASE管理平台。 一键部署会搭建:节点(FISCO-BCOS 2.0)、管理平台(WeBASE-Web)、节点管理子系统(WeBASE-Node-…

3D生物打印的未来:多材料技术的突破

多材料生物打印技术是近年来发展迅速的一项技术,为组织工程和再生医学带来了新的机遇,可以帮助我们更好地理解人体组织的结构和功能,并开发新的治疗方法。 1. 组织构建 复杂性模拟:多材料生物打印技术能够构建具有层次结构和异质…

2022年第十三届蓝桥杯比赛Java B组 【全部真题答案解析-第二部分】

上一篇文章:2022年第十三届蓝桥杯比赛Java B组 【全部真题答案解析-第一部分】_尘封的CPU的博客-CSDN博客最近回顾了Java B组的试题,深有感触:脑子长时间不用会锈住,很可怕。兄弟们,都给我从被窝里爬起来,赶…

综合项目实战--jenkins节点模式

一、DevOps流程 DevOps是一种方法论,是一系列可以帮助开发者和运维人员在实现各自目标的前提下,向自己的客户或用户交付最大化价值及最高质量成果的基本原则和实践,能让开发、测试、运维效率协同工作的方法。 DevOps流程(自动化测试部分) DevOps完整流程 二、gitee+j…

Burpsuite靶场中信息泄露相关的实验通关

目录 第一关:错误消息中的信息披露 第二关:调试页面信息披露 第三关:通过备份文件披露源代码 第四关:通过信息披露绕过身份验证 第五关:版本控制历史中的信息披露 最近看大佬的文章,发现了很对自己没有…

IOS Swift 从入门到精通:ios 连接数据库 安装 Firebase 和 Firestore

创建 Firebase 项目 导航到Firebase 控制台并创建一个新项目。为项目指定任意名称。 在这里插入图片描述 下一步,启用 Google Analytics,因为我们稍后会用到它来发送推送通知。 在这里插入图片描述 在下一个屏幕上,选择您的 Google Analytics 帐户(如果已创建)。如果没…

FFT的IP核使用报错的检查流程

一、config部分 拉出clk resetn, s_axis_config_tdata, s_axis_config_tready, s_axis_config_tvalid .这四个信号。 时序行为解释:

【python - 数据】

一、序列 序列(sequence)是一组有顺序的值的集合,是计算机科学中的一个强大且基本的抽象概念。序列并不是特定内置类型或抽象数据表示的实例,而是一个包含不同类型数据间共享行为的集合。也就是说,序列有很多种类&…

第0章_项目方案介绍

文章目录 第0章 项目方案介绍0.1 功能介绍0.2 硬件方案0.3 软件方案0.3.1 上位机方案0.3.2 **中控方案**0.3.3 **传感器方案**0.3.4 **技术难点** 第0章 项目方案介绍 0.1 功能介绍 本课程来自一个真实项目:多个气体传感器的管理。由于气体传感器比较昂贵&#xf…

mysql5.7安装使用

mysql5.7安装包:百度网盘 提取码: 0000 一、 安装步骤 双击安装文件 选择我接受许可条款–Next 选择自定义安装,下一步 选择电脑对应的系统版本后(我的系统是64位),点击中间的右箭头,选择Next 选择安装路径–Next 执行…

第1章:计算机系统知识

第1章:计算机系统知识 校验码 海明码 1、数据怎么分组,为什么这样分组? 分组1:1、3、5、7 分组2:2、3、6、7 分组3:4、5、6、7 目的就是为了纠错,从下面图便可以知道 2、为什么检验位在2∧…

动态应用安全测试 (DAST) 与渗透测试:应用程序安全测试综合指南

二十多年来,Web 应用程序一直是许多企业的支柱,因此其安全性至关重要。 动态应用程序安全测试 (DAST) 和渗透测试对于识别和缓解 Web 应用程序安全中的安全漏洞至关重要。 虽然两者都旨在增强应用程序安全性,但它们在方法、执行和结果方面存在很大差异。 本综合指南将探讨…

[SAP ABAP] 数据字典

ABAP数据字典是定义和管理数据库对象的工具 系统的所有全局数据类型以及数据库表结构等都需要在数据字典中创建和维护(数据字典中的对象对所有ABAP程序都是全局的) 通过数据字典,我们可以把数据库对象管理好,后续才能顺利的进行功能开发,SA…