当前位置: 首页 > news >正文

01_ddim_inversion_CN

DDIM反转

设置

# !pip install -q transformers diffusers accelerate
import torch
import requests
import torch.nn as nn
import torch.nn.functional as F
from PIL import Image
from io import BytesIO
from tqdm.auto import tqdm
from matplotlib import pyplot as plt
from torchvision import transforms as tfms
from diffusers import StableDiffusionPipeline, DDIMScheduler# Useful function for later
def load_image(url, size=None):response = requests.get(url,timeout=0.2)img = Image.open(BytesIO(response.content)).convert('RGB')if size is not None:img = img.resize(size)return img
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

加载一个已训练的pipeline

# Load a pipeline
pipe = StableDiffusionPipeline.from_pretrained("runwayml/stable-diffusion-v1-5").to(device)
# Set up a DDIM scheduler:
pipe.scheduler = DDIMScheduler.from_config(pipe.scheduler.config)```python
# Sample an image to make sure it is all working
prompt = 'Beautiful DSLR Photograph of a penguin on the beach, golden hour'
negative_prompt = 'blurry, ugly, stock photo'
im = pipe(prompt, negative_prompt=negative_prompt).images[0]
im.resize((256, 256)) # resize for convenient viewing

在这里插入图片描述

DDIM取样过程

在给定时间 t t t, 带噪图像 x t x_t xt 是原始图像( x 0 x_0 x0)与一些噪声 ( ϵ \epsilon ϵ)的叠加。这是在DDIM论文中 x t x_t xt的定义式,我们把它引用到此节里:

x t = α t x 0 + 1 − α t ϵ x_t = \sqrt{\alpha_t}x_0 + \sqrt{1-\alpha_t}\epsilon xt=αt x0+1αt ϵ

ϵ \epsilon ϵ 是一些归一方差的高斯噪声
α t \alpha_t αt (‘alpha’)在DDPM论文中也被叫做 α ˉ \bar{\alpha} αˉ (‘alpha_bar’),被用来定义噪声调度器(scheduler)。在扩散模型中,alpha调度器是被计算出来并排序存储在scheduler.alphas_cumprod中。这令人费解,我理解!我们把这些值画出来,然后在下文中我们会使用DDIM的标注方式。

# Plot 'alpha' (alpha_bar in DDPM language, alphas_cumprod in diffusers for clarity)
timesteps = pipe.scheduler.timesteps.cpu()
alphas = pipe.scheduler.alphas_cumprod[timesteps]
plt.plot(timesteps, alphas, label='alpha_t');
plt.legend();

最初(timestep 0 ,图中左侧)是从一个无噪的干净图像开始, α t = 1 \alpha_t = 1 αt=1。当我们到达更高的timesteps,我们得到一个几乎全是噪声的图像, α t \alpha_t αt也几乎下降到0。

在采样过程,我们从timestep1000的纯噪声开始,慢慢地向timestep0前进。为了计算采样轨迹中的下一时刻( x t − 1 x_{t-1} xt1因为我们是从后向前移动)的值,我们预测噪声( ϵ θ ( x t ) \epsilon_\theta(x_t) ϵθ(xt),这就是我们模型的输出),用它来预测出无噪的图片 x 0 x_0 x0。在这之后我们用这个预测结果朝着’ x t x_t xt的方向’方向移动一小步。最终,我们可以加一些带 σ t \sigma_t σt系数的额外噪声。这是论文中与上述操作相关的章节内容:

在这里插入图片描述

好,我们有了在可控量度噪声下,从 x t x_t xt 移动到 x t − 1 x_{t-1} xt1的公式。今天我们所说案例是不需要再额外添加噪声的 - 即完全确定的DDIM采样。我们来看看这些是如何用代码表达的。

# Sample function (regular DDIM)
@torch.no_grad()
def sample(prompt, start_step=0, start_latents=None,guidance_scale=3.5, num_inference_steps=30,num_images_per_prompt=1, do_classifier_free_guidance=True,negative_prompt='', device=device):# Encode prompttext_embeddings = pipe._encode_prompt(prompt, device, num_images_per_prompt, do_classifier_free_guidance, negative_prompt)# Set num inference stepspipe.scheduler.set_timesteps(num_inference_steps, device=device)# Create a random starting point if we don't have one alreadyif start_latents is None:start_latents = torch.randn(1, 4, 64, 64, device=device)start_latents *= pipe.scheduler.init_noise_sigmalatents = start_latents.clone()for i in tqdm(range(start_step, num_inference_steps)):t = pipe.scheduler.timesteps[i]# expand the latents if we are doing classifier free guidancelatent_model_input = torch.cat([latents] * 2) if do_classifier_free_guidance else latentslatent_model_input = pipe.scheduler.scale_model_input(latent_model_input, t)# predict the noise residualnoise_pred = pipe.unet(latent_model_input, t, encoder_hidden_states=text_embeddings).sample# perform guidanceif do_classifier_free_guidance:noise_pred_uncond, noise_pred_text = noise_pred.chunk(2)noise_pred = noise_pred_uncond + guidance_scale * (noise_pred_text - noise_pred_uncond)# Normally we'd rely on the scheduler to handle the update step:# latents = pipe.scheduler.step(noise_pred, t, latents).prev_sample# Instead, let's do it ourselves:prev_t = max(1, t.item() - (1000//num_inference_steps)) # t-1alpha_t = pipe.scheduler.alphas_cumprod[t.item()]alpha_t_prev = pipe.scheduler.alphas_cumprod[prev_t]predicted_x0 = (latents - (1-alpha_t).sqrt()*noise_pred) / alpha_t.sqrt()direction_pointing_to_xt = (1-alpha_t_prev).sqrt()*noise_predlatents = alpha_t_prev.sqrt()*predicted_x0 + direction_pointing_to_xt# Post-processingimages = pipe.decode_latents(latents)images = pipe.numpy_to_pil(images)return images
# Test our sampling function by generating an image
sample('Watercolor painting of a beach sunset', negative_prompt=negative_prompt, num_inference_steps=50)[0].resize((256, 256))

在这里插入图片描述

看看你是否能把这些代码和论文中的公式对应起来。注意 σ \sigma σ=0是因为我们只注意 无-额外-噪声 的场景,所以我们略去了公式中的那部分。

反转

反转的目标就是’颠倒’取样的过程。我们想最终得到一个带噪的隐式(latent),如果把它作为我们正常取样过程的起始点,结果将生成一副原图像。

这里我们先加载一个原始图像,当然你也可以生成一副图像来代替。

# https://www.pexels.com/photo/a-beagle-on-green-grass-field-8306128/
input_image = load_image('https://images.pexels.com/photos/8306128/pexels-photo-8306128.jpeg', size=(512, 512))
input_image

在这里插入图片描述

我们可以用包含随意分类指引(classifier-free-guidance)的prompt来做反转操作,输入一个图片的描述:

input_image_prompt = "Photograph of a puppy on the grass"

接下来我们来把这个PIL图像变成一些列隐式,它们会被用来当作反转的起点:

# encode with VAE
with torch.no_grad(): latent = pipe.vae.encode(tfms.functional.to_tensor(input_image).unsqueeze(0).to(device)*2-1)
l = 0.18215 * latent.latent_dist.sample()

好了,到有趣的部分了。这个函数看起来和上面的取样函数很像,但我们在timesteps上是在向相反的方向移动,从t=0开始,向越来越多的噪声前进。代替更新隐式时噪声会越来越少,我们估计所预测出的噪声,用它来撤回一步更新操作,把它们从t移动到t+1。

## Inversion
@torch.no_grad()
def invert(start_latents, prompt, guidance_scale=3.5, num_inference_steps=80,num_images_per_prompt=1, do_classifier_free_guidance=True,negative_prompt='', device=device):# Encode prompttext_embeddings = pipe._encode_prompt(prompt, device, num_images_per_prompt, do_classifier_free_guidance, negative_prompt)# latents are now the specified start latentslatents = start_latents.clone()# We'll keep a list of the inverted latents as the process goes onintermediate_latents = []# Set num inference stepspipe.scheduler.set_timesteps(num_inference_steps, device=device)# Reversed timesteps <<<<<<<<<<<<<<<<<<<<timesteps = reversed(pipe.scheduler.timesteps)for i in tqdm(range(1, num_inference_steps), total=num_inference_steps-1):# We'll skip the final iterationif i >= num_inference_steps - 1: continuet = timesteps[i]# expand the latents if we are doing classifier free guidancelatent_model_input = torch.cat([latents] * 2) if do_classifier_free_guidance else latentslatent_model_input = pipe.scheduler.scale_model_input(latent_model_input, t)# predict the noise residualnoise_pred = pipe.unet(latent_model_input, t, encoder_hidden_states=text_embeddings).sample# perform guidanceif do_classifier_free_guidance:noise_pred_uncond, noise_pred_text = noise_pred.chunk(2)noise_pred = noise_pred_uncond + guidance_scale * (noise_pred_text - noise_pred_uncond)current_t = max(0, t.item() - (1000//num_inference_steps))#tnext_t = t # min(999, t.item() + (1000//num_inference_steps)) # t+1alpha_t = pipe.scheduler.alphas_cumprod[current_t]alpha_t_next = pipe.scheduler.alphas_cumprod[next_t]# Inverted update step (re-arranging the update step to get x(t) (new latents) as a function of x(t-1) (current latents)latents = (latents - (1-alpha_t).sqrt()*noise_pred)*(alpha_t_next.sqrt()/alpha_t.sqrt()) + (1-alpha_t_next).sqrt()*noise_pred# Storeintermediate_latents.append(latents)return torch.cat(intermediate_latents)

把它在小狗图片的隐式表达上运行,我们可以在反转的中间过程得到一系列的隐式:

inverted_latents = invert(l, input_image_prompt,num_inference_steps=50)
inverted_latents.shape
  0%|          | 0/49 [00:00<?, ?it/s]torch.Size([48, 4, 64, 64])

我们可以来看一下最终的隐式 - 希望这可以作为我们尝试新的取样过程的起点噪声:

# Decode the final inverted latents:
with torch.no_grad():im = pipe.decode_latents(inverted_latents[-1].unsqueeze(0))
pipe.numpy_to_pil(im)[0]

在这里插入图片描述

你可以把这个反转隐式通过正常的 call 方法来传递给pipeline。

pipe(input_image_prompt, latents=inverted_latents[-1][None], num_inference_steps=50, guidance_scale=3.5).images[0]
  0%|          | 0/50 [00:00<?, ?it/s]

在这里插入图片描述

但这里我们遇见了第一个问题:这 并不是我们一开始的那张图片!这是因为DDIM的反转依赖一个重要的假设,在t时刻预测的噪声与t+1时刻会是相同的 - 这在我们只反转50或100步时是不陈立的。我们可以寄希望于更多的timesteps开得到一个更准确的反转,但我们也可以’作弊’一下,就是说直接从做对应反转过程中的第20/50步的隐式开始:

# The reason we want to be able to specify start step
start_step=20
sample(input_image_prompt, start_latents=inverted_latents[-(start_step+1)][None], start_step=start_step, num_inference_steps=50)[0]
  0%|          | 0/30 [00:00<?, ?it/s]

在这里插入图片描述

距离我们的输入图像已经很接近了!我们为什么要这么做?嗯,这是因为如果我们现在若要用一个新的prompt来生成图像,我们会得到一个匹配于源图像,除了,与新prompt相关的内容。例如,把’小狗’替换为’猫’,我们能看到一只猫在几乎一样草地背景上:

# Sampling with a new prompt
start_step=10
new_prompt = input_image_prompt.replace('puppy', 'cat')
sample(new_prompt, start_latents=inverted_latents[-(start_step+1)][None], start_step=start_step, num_inference_steps=50)[0]
  0%|          | 0/40 [00:00<?, ?it/s]

在这里插入图片描述

为什么不直接用 img2img?

为什么要做反转,不是多此一举吗?为什么不直接对输入图片加入噪声,然后用新的promt直接来去噪呢?我们可以这么做,但这会带来一个到处都被改变得夸张得多的照片(如果我们加入了很多噪声),或哪也没怎么变的图像(如果加了太少的噪声)。来自己试试:

start_step = 10
num_inference_steps=50
pipe.scheduler.set_timesteps(num_inference_steps)
noisy_l = pipe.scheduler.add_noise(l, torch.randn_like(l), pipe.scheduler.timesteps[start_step])
sample(new_prompt, start_latents=noisy_l, start_step=start_step, num_inference_steps=num_inference_steps)[0]
  0%|          | 0/40 [00:00<?, ?it/s]

在这里插入图片描述

注意背景和草坪有着非常大的变化。

把它们都组装起来

来把我们目前所写的代码都组装在一个简单的函数里,输入一张图像和两个prompts,就会得到一个通过反转得到的修改后的图片:

def edit(input_image, input_image_prompt, edit_prompt, num_steps=100, start_step=30, guidance_scale=3.5):with torch.no_grad(): latent = pipe.vae.encode(tfms.functional.to_tensor(input_image).unsqueeze(0).to(device)*2-1)l = 0.18215 * latent.latent_dist.sample()inverted_latents = invert(l, input_image_prompt,num_inference_steps=num_steps)final_im = sample(edit_prompt, start_latents=inverted_latents[-(start_step+1)][None], start_step=start_step, num_inference_steps=num_steps, guidance_scale=guidance_scale)[0]return final_im

And in action:
实际操作起来:

edit(input_image, 'A puppy on the grass', 'an old grey dog on the grass', num_steps=50, start_step=10)
  0%|          | 0/49 [00:00<?, ?it/s]0%|          | 0/40 [00:00<?, ?it/s]

在这里插入图片描述

edit(input_image, 'A puppy on the grass', 'A blue dog on the lawn', num_steps=50, start_step=12, guidance_scale=6)
  0%|          | 0/49 [00:00<?, ?it/s]0%|          | 0/38 [00:00<?, ?it/s]

在这里插入图片描述

相关文章:

01_ddim_inversion_CN

DDIM反转 设置 # !pip install -q transformers diffusers accelerateimport torch import requests import torch.nn as nn import torch.nn.functional as F from PIL import Image from io import BytesIO from tqdm.auto import tqdm from matplotlib import pyplot as p…...

ElasticSearch的文档、字段、映射和高级查询

1. 文档&#xff08;Document&#xff09; 在ES中一个文档是一个可被索引的基础信息单元&#xff0c;也就是一条数据 比如&#xff1a;你可以拥有某一个客户的文档&#xff0c;某一个产品的一个文档&#xff0c;当然&#xff0c;也可以拥有某个订单的一个文档。文档以JSON&…...

vim相关命令讲解!

本文旨在讲解vim 以及其相关的操作&#xff01; 希望读完本文&#xff0c;读者会有一定的收获&#xff01;好的&#xff0c;干货马上就来&#xff01; 初识vim 在讲解vim之前&#xff0c;我们首先要了解vim是什么&#xff0c;有什么作用&#xff1f;只有了解了vim才能更好的理…...

22.构造一个关于员工信息的结构体数组,存储十个员工的信息

结构体问题。构造一个关于员工信息的结构体数组&#xff0c;存储十个员工的信息&#xff0c;包括员工工号&#xff0c;员工工资&#xff0c;员工所得税&#xff0c;员工实发工资。要求工号和工资由键盘输入&#xff0c;并计算出员工所得税&#xff08;所得税工资*0.2&#xff0…...

北京刘家窑中医院举行‘心梗救治日’宣传活动,郭自强主任呼吁提高群众防治意识

...

calico

calico:默认是ip-ip模式&#xff0c; ipip 开销小 vxlan模式&#xff1a;后期版本才支持 不会创建虚拟交换机 Calico 是一种用于构建和管理容器网络的开源软件定义网络&#xff08;SDN&#xff09;解决方案。它专门设计用于在容器和虚拟机之间提供高性能、高可扩展性和灵活的…...

web前端开发第3次Dreamweave课堂练习/html练习代码《网页设计语言基础练习案例》

目标图片&#xff1a; 文字素材&#xff1a; 网页设计语言基础练习案例 ——几个从语义上和文字相关的标签 * h标签&#xff08;h1~h6&#xff09;&#xff1a;用来定义网页的标题&#xff0c;成对出现。 * p标签&#xff1a;用来设置网页的段落&#xff0c;成对出现。 * b…...

APP备案获取安卓app证书公钥获取方法和签名MD5值

前言 在开发和发布安卓应用程序时&#xff0c;了解应用程序证书的公钥和签名MD5值是很重要的。这些信息对于应用程序的安全性和合规性至关重要。现在又因为今年开始APP必须接入备案才能在国内各大应用市场上架&#xff0c;所以获取这两个值成了所有开发者的必经之路。本文将介…...

cefsharp 93.1.140 如何在js中暴露c#类

从cefsharp79版本开始&#xff0c;旧的RegisterJsObject方法被删除了。 也就是说想使用79以后的版本&#xff0c;就必须更新js暴露c#对象的方法了。由于79之前的注册方法是不需要在js中进行注册的&#xff0c;在93版本上如何在不改动前端页面的基础上实现内核升级咧&#xff0c…...

同一台Linux同时安装MYSQL5.7和MYSQL8(第一篇)

在一台Linxu上面同时安装mysql5.7和mysql8.0的步骤&#xff0c;记录一下&#xff0c;方便后续回顾&#xff0c;后续文章之后会接着介绍搭建两台虚拟机一主一从的架构。 其中配置的文件名称、目录、端口号、IP地址要根据自己电脑的实际情况进行更改。 安装完成后效果 [rootzong…...

【CSS】解决上层盒子遮挡下层图片点击事件的三种方法

1. Pointer Events 属性 CSS 的 pointer-events 属性是一个强大的工具&#xff0c;可以控制元素是否接收用户的交互事件。通过将上层盒子的 pointer-events 设置为 none&#xff0c;我们可以确保它不会阻止下层图片的点击事件。 .upper-box {z-index: 999; /* 设置更高的 z-i…...

力扣每日一题 ---- 2906. 构造乘积矩阵

这题很简单(一下就能想到是前缀和的提米)&#xff0c;但是在处理12345上面需要仔细一点&#xff0c;本来我最开始想到的时候全部累乘在除掉当前数&#xff0c;但是这样就没有把12345考虑进去&#xff0c;如果他本身是12345的话&#xff0c;那么除他以外的乘积并不一定是0&#…...

Tomcat学习

一、入门 在webapp里面必须先创建一个文件夹&#xff0c;文件夹里面放的内容&#xff0c;才会被访问到。 创建一个javaweb项目后 二、servlet 1.概述 2.servlet生命周期 3.servlet实例的创建时机 4.Servlet实例的初始化参数 5.HTTP状态码 6.servelet返回JSON数据 7.服务端设置…...

Linux系统上搭建高可用Kafka集群(使用自带的zookeeper)

本次在CentOS7.6上搭建Kafka集群 Apache Kafka 是一个高吞吐量的分布式消息系统&#xff0c;被广泛应用于大规模数据处理和实时数据管道中。本文将介绍在CentOS操作系统上搭建Kafka集群的过程&#xff0c;以便于构建可靠的消息处理平台。 文件分享&#xff08;KafkaUI、kafka…...

WebSocket在node端和客户端的使用

摘要 如果想要实现一个聊天的功能&#xff0c;就会想到使用WebSocket来搭建。那如果没有WebSocet的时候&#xff0c;我们会以什么样的思路来实现聊天功能呢&#xff1f; 假如有一个A页面 和 B页面进行通信&#xff0c;当A发送信息后&#xff0c;我们可以将信息存储在文件或者…...

ENVI IDL:如何将txt文本文件转化为GeoTIFF文件?

01 前言 此处的文本文件形式如下&#xff1a; 里面包含了众多点位信息&#xff08;不是站点数据&#xff09;&#xff0c;我们需要依据上述点的经纬度信息放到对应位置的像素点位置&#xff0c;放置完后如下&#xff1a; 可以发现&#xff0c;还存在部分缺失值&#xff0c;我们…...

北邮22级信通院数电:Verilog-FPGA(9)第九周实验(2)实现下降沿触发的JK触发器(带异步复位和置位功能)

北邮22信通一枚~ 跟随课程进度更新北邮信通院数字系统设计的笔记、代码和文章 持续关注作者 迎接数电实验学习~ 获取更多文章&#xff0c;请访问专栏&#xff1a; 北邮22级信通院数电实验_青山如墨雨如画的博客-CSDN博客 JK.v module JK (input clk,input J,input K,input…...

pyqt5UI同步加载

问题记录&#xff1a;pyqt5 怎样实现修改ui而不改变py代码&#xff0c;例如一个文件存入ui代码&#xff0c;另一个文件引入ui代码 起因&#xff1a;由于在写一个漏扫工具&#xff0c;由于ui的平频繁改动导致主体代码结构变动&#xff0c;所以先有没有方法能够不改变主题代码&am…...

CentOS 7 安装 Redis 5 (单机 6379)

CentOS 7 安装 Redis 5 &#xff08;单机 6379&#xff09; 自己准备好 Redis 5 的安装包并上传至 /opt/ 下的 redis 文件夹下&#xff1a; cd /opt mkdir redis cd redis准备好 Redis 所需的编译环境&#xff1a; yum -y install gcc yum -y install gcc-c解压上传的 Redis…...

sqlplus set参数大区

通过设置不同的SET参数&#xff0c;可以定制SQLPlus的行为和输出格式&#xff1a; SET 参数描述SET AUTOTRACE显示SQL语句的执行计划和统计信息&#xff0c;用于性能优化。SET FEEDBACK控制是否显示SQL语句执行的行数&#xff0c;可提高结果可读性。SET LINESIZE设置每行的最大…...

ubuntu搭建nfs服务centos挂载访问

在Ubuntu上设置NFS服务器 在Ubuntu上&#xff0c;你可以使用apt包管理器来安装NFS服务器。打开终端并运行&#xff1a; sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享&#xff0c;例如/shared&#xff1a; sudo mkdir /shared sud…...

如何在看板中体现优先级变化

在看板中有效体现优先级变化的关键措施包括&#xff1a;采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中&#xff0c;设置任务排序规则尤其重要&#xff0c;因为它让看板视觉上直观地体…...

STM32+rt-thread判断是否联网

一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...

新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案

随着新能源汽车的快速普及&#xff0c;充电桩作为核心配套设施&#xff0c;其安全性与可靠性备受关注。然而&#xff0c;在高温、高负荷运行环境下&#xff0c;充电桩的散热问题与消防安全隐患日益凸显&#xff0c;成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...

是否存在路径(FIFOBB算法)

题目描述 一个具有 n 个顶点e条边的无向图&#xff0c;该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序&#xff0c;确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数&#xff0c;分别表示n 和 e 的值&#xff08;1…...

学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2

每日一言 今天的每一份坚持&#xff0c;都是在为未来积攒底气。 案例&#xff1a;OLED显示一个A 这边观察到一个点&#xff0c;怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 &#xff1a; 如果代码里信号切换太快&#xff08;比如 SDA 刚变&#xff0c;SCL 立刻变&#…...

【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习

禁止商业或二改转载&#xff0c;仅供自学使用&#xff0c;侵权必究&#xff0c;如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...

在Ubuntu24上采用Wine打开SourceInsight

1. 安装wine sudo apt install wine 2. 安装32位库支持,SourceInsight是32位程序 sudo dpkg --add-architecture i386 sudo apt update sudo apt install wine32:i386 3. 验证安装 wine --version 4. 安装必要的字体和库(解决显示问题) sudo apt install fonts-wqy…...

go 里面的指针

指针 在 Go 中&#xff0c;指针&#xff08;pointer&#xff09;是一个变量的内存地址&#xff0c;就像 C 语言那样&#xff1a; a : 10 p : &a // p 是一个指向 a 的指针 fmt.Println(*p) // 输出 10&#xff0c;通过指针解引用• &a 表示获取变量 a 的地址 p 表示…...

ZYNQ学习记录FPGA(一)ZYNQ简介

一、知识准备 1.一些术语,缩写和概念&#xff1a; 1&#xff09;ZYNQ全称&#xff1a;ZYNQ7000 All Pgrammable SoC 2&#xff09;SoC:system on chips(片上系统)&#xff0c;对比集成电路的SoB&#xff08;system on board&#xff09; 3&#xff09;ARM&#xff1a;处理器…...