未验证 提交 c37aac05 编写于 作者: Y YixinKristy 提交者: GitHub

add homework file (#258)

* Add 7day course info on readme

* Update README_cn.md

* Add homework file

* Update homework1.md
上级 7a70cfab
......@@ -31,17 +31,17 @@
**Bonus🤩:鼓励大家除了在AI Studio上完成作业外,也可自行创建GitHub repo,在repo上完成作业(内容可和AI Studio一样),并将PaddleGAN加入你的repo的requirements.txt中,最后将repo链接放在AI Studio项目中即可获得加分,最终有机会获得大奖°˖✧◝(⁰▿⁰)◜✧˖°。**
Day 1:客观题_理论层面的单选题(AI Studio作业入口)
Day 1:[客观题_理论层面的单选题](./homework1)
Day 2:代码题_基于DCGAN,改写为LS-GAN(AI Studio入口&GitHub入口)
Day 2:[代码题_基于DCGAN,改写为LS-GAN](./homework2)
Day 3:代码题_填空补全基于pix2pix实现人脸卡通的预测代码(AI Studio入口&GitHub入口)
Day 3:[代码题_填空补全基于pix2pix实现人脸卡通的预测代码](./homework3)
Day 4:客观题+项目展示(照片、视频)(AI Studio作业入口)
Day 4:客观题+项目展示(照片、视频)
Day 5:客观题+项目展示(照片、视频)(AI Studio作业入口)
Day 5:客观题+项目展示(照片、视频)
Day 6-大作业:自选PaddleGAN里面的模型实现超分(AI Studio入口&GitHub入口)
Day 6-大作业:自选PaddleGAN里面的模型实现超分
## 奖品列表
......
# GAN基础理论客观题
**1. (多选)GAN的基础结构包括()**
A. 生成器
B. 判别器
C. 编码器
D. 解码器
参考答案:AB
**2.(多选)GAN的应用包括()**
A. 换脸
B. 动作迁移
C. 图像翻译
D. 超分辨率
参考答案:ABCD
**3. (多选)生成对抗网络中的生成模型可以()**
A. 输入噪声生成图像
B. 输入噪声和标签生成图像
C. 输入图像生成图像
D. 输入文字描述生成图像
参考答案:ABCD
**4. (单选)下列哪一项是GAN的判别器的损失函数()**
A. ![img](https://user-images.githubusercontent.com/48054808/115173831-b1315300-a0fa-11eb-9616-c8bd39dd74eb.png)
B. ![img](https://user-images.githubusercontent.com/48054808/115173874-c6a67d00-a0fa-11eb-8447-722a4d0993ca.png)
C. ![img](https://user-images.githubusercontent.com/48054808/115173903-d1f9a880-a0fa-11eb-90bd-7c143367444b.png)
D. ![img](https://user-images.githubusercontent.com/48054808/115173943-e178f180-a0fa-11eb-87ce-ba3e96e51572.png)
参考答案:A
**5. (多选)下列关于GAN中对抗的描述正确的是()**
A. 生成器与判别器互相对抗,在对抗中增强
B. 两个神经网络通过相互博弈的方式进行学习
C. 像警察与假钞,在对抗中增强警察的鉴别能力和小偷造假能力
D. 像自然界中捕食者与被捕食者在对抗中的进化
参考答案:ABCD
**6. (多选)下列关于GAN的描述正确的是()**
A. 生成网络希望Fake image的score尽可能的大
B. 生成网络希望Fake image的score尽可能的小
C. 判别网络希望Fake image的score尽可能的大
D. 判别网络希望Fake image的score尽可能的小
参考答案:AD
**7. (多选)下列关于DCGAN的说法正确的有()**
A. 使用卷积代替全连接层
B. 添加BatchNorm
C. 在生成器中使用Relu
D. 在判别器中使用Relu
参考答案:ABC
**8. GAN和auto encoder结构本质的区别是()**
A. 网络结构不同
B. 输入不同
C. 对数据集的要求不同
D. 损失函数不同
参考答案:D
# DCGAN代码改写LSGAN的损失函数
可以看下有提示的地方。
```python
#导入一些必要的包
import os
import random
import paddle
import paddle.nn as nn
import paddle.optimizer as optim
import paddle.vision.datasets as dset
import paddle.vision.transforms as transforms
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
```
```python
dataset = paddle.vision.datasets.MNIST(mode='train',
transform=transforms.Compose([
# resize ->(32,32)
transforms.Resize((32,32)),
# 归一化到-1~1
transforms.Normalize([127.5], [127.5])
]))
dataloader = paddle.io.DataLoader(dataset, batch_size=32,
shuffle=True, num_workers=4)
```
```python
#参数初始化的模块
@paddle.no_grad()
def normal_(x, mean=0., std=1.):
temp_value = paddle.normal(mean, std, shape=x.shape)
x.set_value(temp_value)
return x
@paddle.no_grad()
def uniform_(x, a=-1., b=1.):
temp_value = paddle.uniform(min=a, max=b, shape=x.shape)
x.set_value(temp_value)
return x
@paddle.no_grad()
def constant_(x, value):
temp_value = paddle.full(x.shape, value, x.dtype)
x.set_value(temp_value)
return x
def weights_init(m):
classname = m.__class__.__name__
if hasattr(m, 'weight') and classname.find('Conv') != -1:
normal_(m.weight, 0.0, 0.02)
elif classname.find('BatchNorm') != -1:
normal_(m.weight, 1.0, 0.02)
constant_(m.bias, 0)
```
```python
# Generator Code
class Generator(nn.Layer):
def __init__(self, ):
super(Generator, self).__init__()
self.gen = nn.Sequential(
# input is Z, [B, 100, 1, 1] -> [B, 64 * 4, 4, 4]
nn.Conv2DTranspose(100, 64 * 4, 4, 1, 0, bias_attr=False),
nn.BatchNorm2D(64 * 4),
nn.ReLU(True),
# state size. [B, 64 * 4, 4, 4] -> [B, 64 * 2, 8, 8]
nn.Conv2DTranspose(64 * 4, 64 * 2, 4, 2, 1, bias_attr=False),
nn.BatchNorm2D(64 * 2),
nn.ReLU(True),
# state size. [B, 64 * 2, 8, 8] -> [B, 64, 16, 16]
nn.Conv2DTranspose( 64 * 2, 64, 4, 2, 1, bias_attr=False),
nn.BatchNorm2D(64),
nn.ReLU(True),
# state size. [B, 64, 16, 16] -> [B, 1, 32, 32]
nn.Conv2DTranspose( 64, 1, 4, 2, 1, bias_attr=False),
nn.Tanh()
)
def forward(self, x):
return self.gen(x)
netG = Generator()
# Apply the weights_init function to randomly initialize all weights
# to mean=0, stdev=0.2.
netG.apply(weights_init)
# Print the model
print(netG)
```
```python
class Discriminator(nn.Layer):
def __init__(self,):
super(Discriminator, self).__init__()
self.dis = nn.Sequential(
# input [B, 1, 32, 32] -> [B, 64, 16, 16]
nn.Conv2D(1, 64, 4, 2, 1, bias_attr=False),
nn.LeakyReLU(0.2),
# state size. [B, 64, 16, 16] -> [B, 128, 8, 8]
nn.Conv2D(64, 64 * 2, 4, 2, 1, bias_attr=False),
nn.BatchNorm2D(64 * 2),
nn.LeakyReLU(0.2),
# state size. [B, 128, 8, 8] -> [B, 256, 4, 4]
nn.Conv2D(64 * 2, 64 * 4, 4, 2, 1, bias_attr=False),
nn.BatchNorm2D(64 * 4),
nn.LeakyReLU(0.2),
# state size. [B, 256, 4, 4] -> [B, 1, 1, 1]
nn.Conv2D(64 * 4, 1, 4, 1, 0, bias_attr=False),
# 这里为需要改变的地方
nn.Sigmoid()
)
def forward(self, x):
return self.dis(x)
netD = Discriminator()
netD.apply(weights_init)
print(netD)
```
```python
# Initialize BCELoss function
# 这里为需要改变的地方
loss = nn.BCELoss()
# Create batch of latent vectors that we will use to visualize
# the progression of the generator
fixed_noise = paddle.randn([32, 100, 1, 1], dtype='float32')
# Establish convention for real and fake labels during training
real_label = 1.
fake_label = 0.
# Setup Adam optimizers for both G and D
optimizerD = optim.Adam(parameters=netD.parameters(), learning_rate=0.0002, beta1=0.5, beta2=0.999)
optimizerG = optim.Adam(parameters=netG.parameters(), learning_rate=0.0002, beta1=0.5, beta2=0.999)
```
```python
losses = [[], []]
#plt.ion()
now = 0
for pass_id in range(100):
for batch_id, (data, target) in enumerate(dataloader):
############################
# (1) Update D network: maximize log(D(x)) + log(1 - D(G(z)))
###########################
optimizerD.clear_grad()
real_img = data
bs_size = real_img.shape[0]
label = paddle.full((bs_size, 1, 1, 1), real_label, dtype='float32')
real_out = netD(real_img)
errD_real = loss(real_out, label)
errD_real.backward()
noise = paddle.randn([bs_size, 100, 1, 1], 'float32')
fake_img = netG(noise)
label = paddle.full((bs_size, 1, 1, 1), fake_label, dtype='float32')
fake_out = netD(fake_img.detach())
errD_fake = loss(fake_out,label)
errD_fake.backward()
optimizerD.step()
optimizerD.clear_grad()
errD = errD_real + errD_fake
losses[0].append(errD.numpy()[0])
############################
# (2) Update G network: maximize log(D(G(z)))
###########################
optimizerG.clear_grad()
noise = paddle.randn([bs_size, 100, 1, 1],'float32')
fake = netG(noise)
label = paddle.full((bs_size, 1, 1, 1), real_label, dtype=np.float32,)
output = netD(fake)
errG = loss(output,label)
errG.backward()
optimizerG.step()
optimizerG.clear_grad()
losses[1].append(errG.numpy()[0])
############################
# visualize
###########################
if batch_id % 100 == 0:
generated_image = netG(noise).numpy()
imgs = []
plt.figure(figsize=(15,15))
try:
for i in range(10):
image = generated_image[i].transpose()
image = np.where(image > 0, image, 0)
image = image.transpose((1,0,2))
plt.subplot(10, 10, i + 1)
plt.imshow(image[...,0], vmin=-1, vmax=1)
plt.axis('off')
plt.xticks([])
plt.yticks([])
plt.subplots_adjust(wspace=0.1, hspace=0.1)
msg = 'Epoch ID={0} Batch ID={1} \n\n D-Loss={2} G-Loss={3}'.format(pass_id, batch_id, errD.numpy()[0], errG.numpy()[0])
print(msg)
plt.suptitle(msg,fontsize=20)
plt.draw()
plt.savefig('{}/{:04d}_{:04d}.png'.format('work', pass_id, batch_id), bbox_inches='tight')
plt.pause(0.01)
except IOError:
print(IOError)
paddle.save(netG.state_dict(), "work/generator.params")
```
\ No newline at end of file
# Day 3 作业--Pixel2Pixel:人像卡通化
经过今天的学习,相信大家对图像翻译、风格迁移有了一定的了解啦,是不是也想自己动手来实现下呢?
那么,为了满足大家动手实践的愿望,同时为了巩固大家学到的知识,我们Day 3的作业便是带大家完成一遍课程讲解过的应用--**Pixel2Pixel:人像卡通化**
在本次作业中,大家需要做的是:**补齐代码,跑通训练,提交一张卡通化的成品图,动手完成自己的第一个人像卡通化的应用~**
![](https://ai-studio-static-online.cdn.bcebos.com/6e3af14bf9f847ab92215753fb3b8f61a66186b538f44da78ca56627c35717b8)
## 准备工作:引入依赖 & 数据准备
```python
import paddle
import paddle.nn as nn
from paddle.io import Dataset, DataLoader
import os
import cv2
import numpy as np
from tqdm import tqdm
import matplotlib.pyplot as plt
%matplotlib inline
```
### 数据准备:
- 真人数据来自[seeprettyface](http://www.seeprettyface.com/mydataset.html)
- 数据预处理(详情见[photo2cartoon](https://github.com/minivision-ai/photo2cartoon)项目)。
<div>
<img src='https://ai-studio-static-online.cdn.bcebos.com/c56c889827534363a8b6909d7737a1da64635ad33e1e44cb822f4c1cf1dfc689' >
</div>
- 使用[photo2cartoon](https://github.com/minivision-ai/photo2cartoon)项目生成真人数据对应的卡通数据。
```python
# 解压数据
!unzip -q data/data79149/cartoon_A2B.zip -d data/
```
### 数据可视化
```python
# 训练数据统计
train_names = os.listdir('data/cartoon_A2B/train')
print(f'训练集数据量: {len(train_names)}')
# 测试数据统计
test_names = os.listdir('data/cartoon_A2B/test')
print(f'测试集数据量: {len(test_names)}')
# 训练数据可视化
imgs = []
for img_name in np.random.choice(train_names, 3, replace=False):
imgs.append(cv2.imread('data/cartoon_A2B/train/'+img_name))
img_show = np.vstack(imgs)[:,:,::-1]
plt.figure(figsize=(10, 10))
plt.imshow(img_show)
plt.show()
```
```python
class PairedData(Dataset):
def __init__(self, phase):
super(PairedData, self).__init__()
self.img_path_list = self.load_A2B_data(phase) # 获取数据列表
self.num_samples = len(self.img_path_list) # 数据量
def __getitem__(self, idx):
img_A2B = # 读取一组数据
img_A2B = # 从0~255归一化至-1~1
img_A2B = # 维度变换HWC -> CHW
img_A = # 真人照
img_B = # 卡通图
return img_A, img_B
def __len__(self):
return self.num_samples
@staticmethod
def load_A2B_data(phase):
assert phase in ['train', 'test'], "phase should be set within ['train', 'test']"
# 读取数据集,数据中每张图像包含照片和对应的卡通画。
data_path = 'data/cartoon_A2B/'+phase
return [os.path.join(data_path, x) for x in os.listdir(data_path)]
```
```python
paired_dataset_train = PairedData('train')
paired_dataset_test = PairedData('test')
```
## 第一步:搭建生成器
### 请大家补齐空白处的代码,‘#’ 后是提示。
```python
class UnetGenerator(nn.Layer):
def __init__(self, input_nc=3, output_nc=3, ngf=64):
super(UnetGenerator, self).__init__()
self.down1 = nn.Conv2D(input_nc, ngf, kernel_size=4, stride=2, padding=1)
self.down2 = Downsample(ngf, ngf*2)
self.down3 = Downsample(ngf*2, ngf*4)
self.down4 = Downsample(ngf*4, ngf*8)
self.down5 = Downsample(ngf*8, ngf*8)
self.down6 = Downsample(ngf*8, ngf*8)
self.down7 = Downsample(ngf*8, ngf*8)
self.center = Downsample(ngf*8, ngf*8)
self.up7 = Upsample(ngf*8, ngf*8, use_dropout=True)
self.up6 = Upsample(ngf*8*2, ngf*8, use_dropout=True)
self.up5 = Upsample(ngf*8*2, ngf*8, use_dropout=True)
self.up4 = Upsample(ngf*8*2, ngf*8)
self.up3 = Upsample(ngf*8*2, ngf*4)
self.up2 = Upsample(ngf*4*2, ngf*2)
self.up1 = Upsample(ngf*2*2, ngf)
self.output_block = nn.Sequential(
nn.ReLU(),
nn.Conv2DTranspose(ngf*2, output_nc, kernel_size=4, stride=2, padding=1),
nn.Tanh()
)
def forward(self, x):
d1 = self.down1(x)
d2 = self.down2(d1)
d3 = self.down3(d2)
d4 = self.down4(d3)
d5 = self.down5(d4)
d6 = self.down6(d5)
d7 = self.down7(d6)
c = self.center(d7)
x = self.up7(c, d7)
x = self.up6(x, d6)
x = self.up5(x, d5)
x = self.up4(x, d4)
x = self.up3(x, d3)
x = self.up2(x, d2)
x = self.up1(x, d1)
x = self.output_block(x)
return x
class Downsample(nn.Layer):
# LeakyReLU => conv => batch norm
def __init__(self, in_dim, out_dim, kernel_size=4, stride=2, padding=1):
super(Downsample, self).__init__()
self.layers = nn.Sequential(
# LeakyReLU, leaky=0.2
# Conv2D
# BatchNorm2D
)
def forward(self, x):
x = self.layers(x)
return x
class Upsample(nn.Layer):
# ReLU => deconv => batch norm => dropout
def __init__(self, in_dim, out_dim, kernel_size=4, stride=2, padding=1, use_dropout=False):
super(Upsample, self).__init__()
sequence = [
# ReLU
# Conv2DTranspose
# nn.BatchNorm2D
]
if use_dropout:
sequence.append(nn.Dropout(p=0.5))
self.layers = nn.Sequential(*sequence)
def forward(self, x, skip):
x = self.layers(x)
x = paddle.concat([x, skip], axis=1)
return x
```
## 第二步:鉴别器的搭建
### 请大家补齐空白处的代码,‘#’ 后是提示。
```python
class NLayerDiscriminator(nn.Layer):
def __init__(self, input_nc=6, ndf=64):
super(NLayerDiscriminator, self).__init__()
self.layers = nn.Sequential(
nn.Conv2D(input_nc, ndf, kernel_size=4, stride=2, padding=1),
nn.LeakyReLU(0.2),
ConvBlock(ndf, ndf*2),
ConvBlock(ndf*2, ndf*4),
ConvBlock(ndf*4, ndf*8, stride=1),
nn.Conv2D(ndf*8, 1, kernel_size=4, stride=1, padding=1),
nn.Sigmoid()
)
def forward(self, input):
return self.layers(input)
class ConvBlock(nn.Layer):
# conv => batch norm => LeakyReLU
def __init__(self, in_dim, out_dim, kernel_size=4, stride=2, padding=1):
super(ConvBlock, self).__init__()
self.layers = nn.Sequential(
# Conv2D
# BatchNorm2D
# LeakyReLU, leaky=0.2
)
def forward(self, x):
x = self.layers(x)
return x
```
```python
generator = UnetGenerator()
discriminator = NLayerDiscriminator()
```
```python
out = generator(paddle.ones([1, 3, 256, 256]))
print('生成器输出尺寸:', out.shape) # 应为[1, 3, 256, 256]
out = discriminator(paddle.ones([1, 6, 256, 256]))
print('鉴别器输出尺寸:', out.shape) # 应为[1, 1, 30, 30]
```
```python
# 超参数
LR = 1e-4
BATCH_SIZE = 8
EPOCHS = 100
# 优化器
optimizerG = paddle.optimizer.Adam(
learning_rate=LR,
parameters=generator.parameters(),
beta1=0.5,
beta2=0.999)
optimizerD = paddle.optimizer.Adam(
learning_rate=LR,
parameters=discriminator.parameters(),
beta1=0.5,
beta2=0.999)
# 损失函数
bce_loss =
l1_loss =
# dataloader
data_loader_train = DataLoader(
paired_dataset_train,
batch_size=BATCH_SIZE,
shuffle=True,
drop_last=True
)
data_loader_test = DataLoader(
paired_dataset_test,
batch_size=BATCH_SIZE
)
```
```python
results_save_path = 'work/results'
os.makedirs(results_save_path, exist_ok=True) # 保存每个epoch的测试结果
weights_save_path = 'work/weights'
os.makedirs(weights_save_path, exist_ok=True) # 保存模型
for epoch in range(EPOCHS):
for data in tqdm(data_loader_train):
real_A, real_B = data
optimizerD.clear_grad()
# D([real_A, real_B])
real_AB = paddle.concat((real_A, real_B), 1)
d_real_predict = discriminator(real_AB)
d_real_loss = bce_loss(d_real_predict, paddle.ones_like(d_real_predict))
# D([real_A, fake_B])
fake_B =
fake_AB =
d_fake_predict =
d_fake_loss =
# train D
d_loss = (d_real_loss + d_fake_loss) / 2.
d_loss.backward()
optimizerD.step()
optimizerG.clear_grad()
# D([real_A, fake_B])
fake_B =
fake_AB =
g_fake_predict =
g_bce_loss =
g_l1_loss =
g_loss = g_bce_loss + g_l1_loss * 100.
# train G
g_loss.backward()
optimizerG.step()
print(f'Epoch [{epoch+1}/{EPOCHS}] Loss D: {d_loss.numpy()}, Loss G: {g_loss.numpy()}')
if (epoch+1) % 10 == 0:
paddle.save(generator.state_dict(), os.path.join(weights_save_path, 'epoch'+str(epoch+1).zfill(3)+'.pdparams'))
# test
generator.eval()
with paddle.no_grad():
for data in data_loader_test:
real_A, real_B = data
break
fake_B = generator(real_A)
result = paddle.concat([real_A[:3], real_B[:3], fake_B[:3]], 3)
result = result.detach().numpy().transpose(0, 2, 3, 1)
result = np.vstack(result)
result = (result * 127.5 + 127.5).astype(np.uint8)
cv2.imwrite(os.path.join(results_save_path, 'epoch'+str(epoch+1).zfill(3)+'.png'), result)
generator.train()
```
## 最后:用你补齐的代码试试卡通化的效果吧!
```python
# 为生成器加载权重
last_weights_path = os.path.join(weights_save_path, sorted(os.listdir(weights_save_path))[-1])
print('加载权重:', last_weights_path)
model_state_dict = paddle.load(last_weights_path)
generator.load_dict(model_state_dict)
generator.eval()
```
```python
# 读取数据
test_names = os.listdir('data/cartoon_A2B/test')
img_name = np.random.choice(test_names)
img_A2B = cv2.imread('data/cartoon_A2B/test/'+img_name)
img_A = img_A2B[:, :256] # 真人照
img_B = img_A2B[:, 256:] # 卡通图
g_input = img_A.astype('float32') / 127.5 - 1 # 归一化
g_input = g_input[np.newaxis, ...].transpose(0, 3, 1, 2) # NHWC -> NCHW
g_input = paddle.to_tensor(g_input) # numpy -> tensor
g_output = generator(g_input)
g_output = g_output.detach().numpy() # tensor -> numpy
g_output = g_output.transpose(0, 2, 3, 1)[0] # NCHW -> NHWC
g_output = g_output * 127.5 + 127.5 # 反归一化
g_output = g_output.astype(np.uint8)
img_show = np.hstack([img_A, g_output])[:,:,::-1]
plt.figure(figsize=(8, 8))
plt.imshow(img_show)
plt.show()
```
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册