简单扩散

 

让我们直接来看看代码 

#include <iostream>
#include <conio.h>

void main()
{
	const int w = 10;
	const int h = 10;
	int map[w*h] = 
	{
		0,0,0,0,1,0,0,0,0,0,
		0,0,1,1,1,1,0,0,0,0,
		0,1,0,0,0,0,1,0,0,0,
		0,1,0,0,0,0,0,1,0,0,
		0,1,0,0,0,0,0,0,1,0,
		0,1,0,0,0,0,0,0,1,0,
		0,1,0,1,1,1,0,0,1,0,
		0,1,0,1,0,1,0,1,1,0,
		0,1,1,1,0,1,1,1,0,0,
		0,0,0,0,0,0,0,0,0,0
	};
	//翻开与否的数组
	bool show[w*h] = {};

	//光标
	int px = 0; 
	int py = 0;

	while (1)
	{
		system("cls");
		for (int i = 0;i < w*h; ++i)
		{
			if (i == px + py * w)
				std::cout<<"光";
			else if (show[i])
			{
				if (map[i] == 1)
					std::cout<<"①";
				else if (map[i] == 0)
					std::cout<<"  ";
			}
			else
			{
				std::cout<<"■";
			}
			if (i % w== w-1)
				std::cout<<std::endl;
		}

		int a = _getch();
		if (a == 'w')
		{
			if (py > 0) py -- ;
		}
		else if (a == 's')
		{
			if (py < h-1) py ++;
		}
		else if (a == 'a')
		{
			if (px > 0) px --;
		}
		else if (a == 'd')
		{
			if (px < w - 1) px ++;
		}
		else if (a == ' ')
		{
			//如果没有翻开
			if (!show[px+py*w])
			{
				if (map[px+py*w] == 1)
					show[px+py*w] = true;
				else
				{
					int A[w*h];					
					int len = 0;
					A[len++] = px+py*w;//把点击的位置装入A中
					for (int i = 0;i < len; ++i)
					{
						if (map[A[i]] == 0)
						{
							int xx[] = {0,0,-1,1};
							int yy[] = {-1,1,0,0};
							//循环四个方向
							for (int k = 0; k < 4; ++k)
							{
								int x = A[i] % w + xx[k];
								int y = A[i] / w + yy[k];
								//如果没有出界
								if (x >= 0 && x < w && y >= 0 && y < h)
								{
									//如果是黄色直接翻开
									if (map[x+y*w] == 1)
										show[x+y*w] = true;
									else
									{
										//判断x+y*w在不在A表中,不在才装入A表
										bool zai = false;
										for (int i = 0; i < len; ++i)
										{	if (A[i] == x+y*w)
											{
												zai=true;
												break;
											}
										}
										if (!zai)
											A[len++] = x+y*w;
									}
								}
							}
							
						}
					}
					//在A表中的所有下标都要翻开
					for (int i = 0;i < len; ++i)
					{
						show[A[i]] = true;
					}

				}
			}
		}
	}


}

 

为了使用 PyTorch 实现一个简单扩散模型,需要遵循一系列关键步骤,包括定义模型架构、构建数据管道、训练过程以及采样生成新图像。以下是一个基于去噪扩散概率模型(DDPM)的实现框架。 ### 1. 模型架构设计 首先,定义一个神经网络用于预测噪声。通常,这个网络会是一个 U-Net 架构,但为了简化示例,这里采用一个基本的卷积网络: ```python class SimpleUNet(nn.Module): def __init__(self, in_channels=3, out_channels=3): super().__init__() self.down1 = nn.Conv2d(in_channels, 64, kernel_size=3, stride=2, padding=1) self.down2 = nn.Conv2d(64, 128, kernel_size=3, stride=2, padding=1) self.up1 = nn.ConvTranspose2d(128, 64, kernel_size=4, stride=2, padding=1) self.up2 = nn.ConvTranspose2d(64, out_channels, kernel_size=4, stride=2, padding=1) def forward(self, x, t): # 嵌入时间步长到输入中 x = F.relu(self.down1(x)) x = F.relu(self.down2(x)) x = F.relu(self.up1(x)) x = self.up2(x) return x ``` ### 2. 时间嵌入编码 在 DDPM 中,时间步长信息通过正弦或学习的嵌入方式添加到输入中。这里展示的是正弦时间步嵌入[^2]: ```python class SinusoidalEmbeddings(nn.Module): def __init__(self, time_steps: int, embed_dim: int): super().__init__() position = torch.arange(time_steps).unsqueeze(1).float() div = torch.exp(torch.arange(0, embed_dim, 2).float() * -(math.log(10000.0) / embed_dim)) embeddings = torch.zeros(time_steps, embed_dim, requires_grad=False) embeddings[:, 0::2] = torch.sin(position * div) embeddings[:, 1::2] = torch.cos(position * div) self.embeddings = embeddings def forward(self, x, t): embeds = self.embeddings[t].to(x.device) return embeds[:, :, None, None] ``` ### 3. 数据预处理和加载 使用 `torchvision` 加载数据集并进行标准化处理: ```python transform = transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,)) ]) dataset = datasets.MNIST(root='./data', train=True, transform=transform, download=True) dataloader = DataLoader(dataset, batch_size=128, shuffle=True) ``` ### 4. 扩散过程设置 定义前向扩散过程中的参数,例如噪声调度和时间步数: ```python def get_noise_schedule(num_steps, beta_start=1e-4, beta_end=0.02): betas = torch.linspace(beta_start, beta_end, num_steps) alphas = 1. - betas alphas_cumprod = torch.cumprod(alphas, axis=0) return betas, alphas_cumprod ``` ### 5. 训练循环 编写训练函数以迭代优化模型: ```python device = 'cuda' if torch.cuda.is_available() else 'cpu' model = SimpleUNet().to(device) optimizer = optim.Adam(model.parameters(), lr=1e-3) betas, alphas_cumprod = get_noise_schedule(1000) num_epochs = 10 for epoch in range(num_epochs): for images, _ in tqdm(dataloader): images = images.to(device) optimizer.zero_grad() # 随机选择时间步 t = torch.randint(0, 1000, (images.size(0),), device=device) # 添加噪声 noise = torch.randn_like(images) sqrt_alpha_cumprod = torch.sqrt(alphas_cumprod[t]).view(-1, 1, 1, 1) sqrt_one_minus_alpha_cumprod = torch.sqrt(1. - alphas_cumprod[t]).view(-1, 1, 1, 1) noisy_images = sqrt_alpha_cumprod * images + sqrt_one_minus_alpha_cumprod * noise # 预测噪声 predicted_noise = model(noisy_images, t) loss = F.mse_loss(predicted_noise, noise) loss.backward() optimizer.step() ``` ### 6. 图像生成(采样) 训练完成后,可以通过反向扩散过程生成新样本: ```python @torch.no_grad() def sample_image(model, img_shape=(1, 28, 28), num_steps=1000): model.eval() x = torch.randn(img_shape, device=device) for i in reversed(range(num_steps)): t = torch.full((x.shape[0],), i, device=device) predicted_noise = model(x, t) alpha = 1. - betas[t] alpha_cumprod = alphas_cumprod[t] beta = betas[t] noise = torch.randn_like(x) if i > 1 else 0. x = (x - ((1 - alpha) / torch.sqrt(1 - alpha_cumprod)) * predicted_noise) / torch.sqrt(alpha) x += torch.sqrt(beta) * noise model.train() return x.cpu().numpy() ``` ### 7. 可视化结果 最后,可以绘制生成的图像以验证模型效果: ```python sampled_images = sample_image(model) plt.imshow(sampled_images[0][0], cmap='gray') plt.axis('off') plt.show() ``` ##
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值