Image Super-Resolution via Sparse Representation——基于稀疏表示的超分辨率重建

2023-10-27

  经典超分辨率重建论文,基于稀疏表示。下面首先介绍稀疏表示,然后介绍论文的基本思想和算法优化过程,最后使用python进行实验。

稀疏表示

  稀疏表示是指,使用过完备字典中少量向量的线性组合来表示某个元素。过完备字典是一个列数大于行数的行满秩矩阵,也就是说,它的列向量有无数种线性组合来表达列向量空间中的任意点。由于它的列数通常远大于行数,可以使用占比很小的列向量来表示特定的向量,我们称这种表示为稀疏表示。

  那么如何获得这个字典呢?它在特定的任务下有特定的取值。和炼丹类似,我们先要用大量数据来训练这个矩阵,让它提取出能稀疏表示这些数据的特征,进而拥有稀疏表示其它相似数据的能力。

  训练过完备字典的过程称为稀疏编码。设训练数据集为矩阵$X=(x_1,x_2,...,x_n)\in R^{m\times n}$,待训练矩阵为$A\in R^{m\times K}$,矩阵对每一数据的表示权重为$\alpha = (\alpha_1,\alpha_2,...,\alpha_n)\in R^{K\times n}$。进行如下优化:

\begin{align} \min\limits_{A,\alpha}\|\alpha\|_0\;\;\;s.t. \;  \|A\alpha - X\|_2^2\le \epsilon \end{align}

  容易理解,约束重建向量与原始向量差异的同时,优化表示权重$\alpha$的稀疏性。通过优化获得所需的过完备字典后,我们就可以用它来稀疏表示新的数据了。对于某个向量$y$,我们可以进行类似的优化来获得它在字典中的稀疏表示:

\begin{align} \min\limits_{\alpha}\|\alpha\|_0\;\;\;s.t. \;  \|A\alpha - y\|_2^2\le \epsilon \end{align}

  因为零范数的离散性,以上优化是NP-难问题,无法用正常的优化算法解决。所以通常会对上式进行调整,以方便优化。而在线性约束下,对一范数的优化有稀疏性(点击链接理解),因此可以转换为对一范数的优化。然后根据拉格朗日乘子法(据说如此,但我觉得这个转换并不等价),不等式约束可以移入优化中:

\begin{align} \min\limits_{\alpha} \lambda \|\alpha\|_1 + \|A\alpha - y\|_2^2 \end{align}

  同样,$(1)$式也可以进行类似的转换。

  以上就是稀疏表示的流程,看到这个提取特征然后重建的过程,我们会联想到主成分分析(PCA)。PCA能使我们方便地找到一组“完备”基向量,但是这里我们要做的是找到一组“过完备”的基向量来表示输入向量。过完备基的好处是它们能更有效地找出隐含在输入数据内部的结构与模式。然而,与PCA不同,对于过完备基来说,系数$\alpha$不再由输入向量$y$单独确定。因此,在稀疏编码算法中,我们另加一个评判标准“稀疏性”来解决因过完备而导致的退化(degeneracy)问题。

  上面这段是百度百科原话。我觉得,把过完备字典与神经网络进行对比,可以把这个待训练的很“宽”的矩阵看做参数量很大的网络。我们知道参数量大而训练数据不充足的时候模型很容易过拟合,为了防止过拟合就要加上正则项,以使参数能专注于学习更有共性的特征。我们可以把上面的稀疏性看做正则化来理解,使字典的列向量能表达一些更有“特点”的信息。

论文原理及实现流程

基本思想

  在训练阶段,论文同时对LR训练集$Y= (y_1,y_2,...,y_n)$和对应的HR训练集$X = (x_1,x_2,...,x_n)$分别训练两个过完备字典$D_l,D_h$,使得LR数据$y_i$和它对应的HR数据$x_i$能以相同的稀疏编码$\alpha_i$分别被$D_l$和$D_h$表示。也就是

$\left\{ \begin{aligned} &D_l\alpha_i \approx y_i \\ &D_h\alpha_i \approx x_i \end{aligned} \right.$

  在测试阶段,我们已经有了训练好的$D_l$和相对应的$D_h$。对于测试图像$y_t$,首先通过优化获得$y_t$在$D_l$中的稀疏表示$\alpha_t$,此时有$D_l\alpha_t \approx y_t$。然后用这个表示通过$D_h$映射出对应的SR图像,即$\hat{x}_t=D_h\alpha_t$。

训练过程

  训练过程就是训练上述的过完备字典对。因为性能的因素,我们不可能直接对整张图进行稀疏编码,论文是将图像分为方形的区块(patch)进行编码的。因此,用于训练的成对数据不是整张的LR-HR图像对,而是所有图像分割开来的区块对。现在把LR训练集的所有区块表示为$Y=(y_1,y_2,...,y_n)\in R^{M\times n}$,相应的HR训练集区块表示为$X = (x_1,x_2,...,x_n)\in R^{N\times n}$。如果放大倍数为$t$倍,则有$N=t^2M$。

  优化式很直观:

\begin{align} \min\limits_{D_l,D_h,\alpha}\frac{1}{N}\|X - D_h\alpha\|_2^2+\frac{1}{M}\|Y - D_l\alpha\|_2^2 + \lambda \|\alpha\|_1 \end{align}

  其中$D_l\in R^{M\times K},D_h\in R^{N\times K}$,分别表示待训练的LR和HR字典,$K$表示字典的原子数;$\alpha\in R^{K\times n}$为表示矩阵;$\lambda$为平衡稀疏性和重建一致性的系数。一二两项惩罚使用相同表示的重建差异,第三项用来优化表示的稀疏性。把前两项合并,可得:

\begin{aligned} \min\limits_{D_c,\alpha}\|X_c - D_c\alpha\|_2^2 + \lambda \|\alpha\|_1 \end{aligned}

  其中

$X_c = \left[ \begin{aligned} &\frac{1}{\sqrt{N}}X\\ &\frac{1}{\sqrt{M}}Y \end{aligned} \right], D_c = \left[ \begin{aligned} &\frac{1}{\sqrt{N}}D_h\\ &\frac{1}{\sqrt{M}}D_l \end{aligned} \right]$

  论文说同时优化$D_c$和$\alpha$非凸,但是固定其中一个变量,然后对另一个变量的优化则是凸的。因此可以将凸优化交替进行,最终可以达到一个局部最优点。然而我还是选择无脑梯度下降算了。当然我们可以使用SGD,每次随机选择部分区块执行迭代,这样做的好处在于可以引入随机性从而增加跳出局部最优的可能性。引人注意的是,执行SGD时,待优化的权重是$D_c$和$\alpha$,但由于每次只选择部分区块,$\alpha$也只能选择对应的那部分进行更新,这有点像Dropout。但是,后面实验的时候发现,SGD的效果并没有GD好,因此没有分成小批量来迭代。

推理过程

  在获得$D_l$和$D_h$后,就可以用它们对LR图像进行重建了。论文采用扫描的方式,一个区块一个区块从上到下、从左到右对测试图像进行超分辨率重建。另外,为了使相邻区块之间能相互匹配,防止颜色上的冲突,前后两个区块之间设有重叠部分,在重建一个区块时,重叠部分要和上一个区块一致。具体优化方式如下。

  首先将测试图像$y$按顺序划分为$m$个区块$(p_1,p_2,...,p_m)$,设区块在$D_l$中的表示为$(\alpha_1,\alpha_2,...,\alpha_m)$。按顺序对所有区块执行优化,对于第$i$个区块,优化式如下:

\begin{align} \min\limits_{\alpha_i} \lambda\|\alpha_i\|_1 + \|FD_l\alpha_i - Fp_i\|_2^2+ \|PD_h\alpha_i - w\|_2^2 \end{align}

  其中$w$表示已重建区块和当前区块的重叠部分,$P$表示将当前区块映射为重叠部分的矩阵。至于$F$,论文说是一个线性提取器,使图像中感知效果更好。论文实验时用的是一阶、二阶导数滤波器,但没说清楚具体如何操作,我实验就没有用。

  式子意义很明显,第一项保证表示的稀疏性,第二项优化原始LR图像的重建一致性,第三项优化SR图像相邻区块重叠部分的一致性。获得SR图像所有区块的稀疏表示后,左乘$D_h$,然后将区块拼接起来,就是最终的SR图像了。

  除了以上步骤以外,论文还多了一个所谓全局重建约束。用什么反向投影法,通过迭代让SR图像退化后能和原始图像更相似。由于说的很不清楚,这里就不加了,而且我觉得这不是这篇论文的主要内容。

  另外,论文在执行推理过程之前,先将原图减去自身元素的均值,以使模型能更专注于纹理的重建,在重建完的SR图像上再加回这个均值。但是这个策略只在推理章节提了一句,在训练$D_l,D_h$时是否使用标准化的图像并没有说明。

实验与分析

  实验使用LSUN数据集中的bedroom作为训练集,从中选取1024张长宽都大于256像素的图片,居中裁剪至256x256,获得HR训练集。然后对HR使用Bicubic缩小4倍至64x64,获得LR训练集。将LR区块划分为4x4大小,HR区块划分为16x16大小,则每张图片都可被划分为16x16个区块。另外定义$D_l$和$D_h$的原子(列向量)数为2560(算力有限),又由于彩色图片有三个通道,因此$D_l$和$D_h$的列向量长度分别为$4\times 4 \times 3$和$16\times 16 \times 3$。

训练

  综上,对于$(4)$式中的各个参数,有:

\begin{equation} \left\{ \begin{aligned} &X \in R^{(16\times 16\times 3)\times (1024\times 16^2)}\\ &Y \in R^{(4\times 4\times 3)\times (1024\times 16^2)}\\ &D_h \in R^{(16\times 16\times 3)\times 2560}\\ &D_l \in R^{(4\times 4\times 3)\times 2560}\\ &\alpha \in R^{2560\times (1024\times 16^2)}\\ \end{aligned} \right. \end{equation}

  另设$(4)$式$\lambda=0.1$,使用RMSProp对$(4)$式进行优化,根据以上所列参数,Pytorch代码如下:

#%%
import torch,os
import numpy as np
import matplotlib.pyplot as plt
from torch import optim,cuda

#读取图像
LR_path = r'E:\DataSets\SRTest\LR'
HR_path = r'E:\DataSets\SRTest\HR'
LR_imgs = np.zeros([1024,64,64,3])
HR_imgs = np.zeros([1024,256,256,3])

for i, j in zip(os.listdir(LR_path),range(1024)):
  img_path = os.path.join(LR_path,i)
  LR_imgs[j] = plt.imread(img_path)/255
for i, j in zip(os.listdir(HR_path),range(1024)):
  img_path = os.path.join(HR_path,i)
  HR_imgs[j] = plt.imread(img_path)/255
 
#定义各个变量
def imgs2patches(imgs, patch_size):
  #将图像集转换为区块集
  imgs_n = len(imgs)
  patch_n = int(imgs.shape[1]/patch_size)
  patches = np.zeros([imgs_n*patch_n**2, patch_size*patch_size*3]) 
  for i in range(patch_n): 
    for j in range(patch_n):
      t = imgs[:,i*patch_size:(i+1)*patch_size,j*patch_size:(j+1)*patch_size,:]
      t = np.reshape(t,[imgs_n,-1]) 
      now = i * patch_n + j
      patches[imgs_n*now:imgs_n*(now+1),:] = t
  return patches.T

atom_n = 2560

X = torch.tensor(imgs2patches(HR_imgs, 16),device='cuda')*255 #训练集图像元素色值取值在[0,255]
Y = torch.tensor(imgs2patches(LR_imgs, 4), device='cuda')*255
Dh = torch.normal(0,1,[16*16*3,atom_n],device='cuda') 
Dl = torch.normal(0,1,[4*4*3,atom_n],device='cuda') 
 
alpha = torch.normal(0,1,[atom_n,1024*16*16],device='cuda') 
Dh.requires_grad_(True)
Dl.requires_grad_(True)
alpha.requires_grad_(True)
opt = optim.RMSprop([Dh,Dl,alpha]) 
#%%
#训练模型
from torch.utils.tensorboard import SummaryWriter 

writer = SummaryWriter('logs/')
def iter_one_epoch(lamb=0.01):
  patch_n = alpha.shape[1]
  term1 = torch.sum((X - torch.matmul(Dh,alpha))**2)/256/patch_n
  term2 = torch.sum((Y - torch.matmul(Dl,alpha))**2)/16/patch_n
  term3 = lamb * torch.sum(torch.abs(alpha))/patch_n
  loss = term1 + term2 + term3
  opt.zero_grad()
  loss.backward()
  opt.step()
  return term1,term2,term3,loss
 
for i in range(1, 1500): 
  term1,term2,term3,loss = iter_one_epoch(lamb=0.1)
  print(i,loss.cpu().detach().numpy())  
  writer.add_scalar('term1', term1, int(i))
  writer.add_scalar('term2', term2, int(i))
  writer.add_scalar('term3', term3, int(i))
  writer.add_scalar('loss', loss, int(i))
  if i % 700 == 0: 
    for i in opt.param_groups: 
      i['lr'] = i['lr']*0.5 
print("保存字典")
torch.save(Dl,'dictionaries/Dic_LR')#保存两个字典 
torch.save(Dh,'dictionaries/Dic_HR') 
#%%
#用Dh重建HR图像验证训练结果
def get_recon_LR_HR(n): 
  print(Dh.shape,Dl.shape)
 
  recon_LR = torch.matmul(Dl, alpha)
  recon_HR = torch.matmul(Dh, alpha) 
  LR = torch.zeros([1024,64,64,3],device='cuda')
  HR = torch.zeros([1024,256,256,3],device='cuda') 
  
  for i in range(n): 
    print(i)
    for j in range(16):
      for k in range(16): 
        LR[i,4*j:4*(j+1),4*k:4*(k+1),:] = recon_LR[:,i+(j*16+k)*1024].reshape([4,4,3])
        HR[i,16*j:16*(j+1),16*k:16*(k+1),:] = recon_HR[:,i+(j*16+k)*1024].reshape([16,16,3])
  return LR,HR 
lr,hr = get_recon_LR_HR(100) 
n = 10
fig = plt.figure(figsize=(15,15))
ax1,ax2,ax3,ax4 = fig.add_subplot(221),fig.add_subplot(222),fig.add_subplot(223),fig.add_subplot(224)
ax1.imshow(LR_imgs[n])
ax2.imshow(lr[n].cpu().detach()/255)
ax3.imshow(HR_imgs[n])
ax4.imshow(hr[n].cpu().detach()/255)
ax1.set_title('LR image',fontsize=20)
ax2.set_title('Reconstructed LR image',fontsize=20)
ax3.set_title('HR image',fontsize=20)
ax4.set_title('Reconstructed HR image',fontsize=20)
plt.show()   

  我另外对比过Adam和原始GD,迭代速度都没有RMSProp快,而且loss在稳定后是最小的。算法总共迭代了1500次,使用的是RMSProp默认的学习率,但每700次迭代都会下调为原来的一半。整个迭代在3090下用时10分钟,loss变化如下:

  以下是训练集的LR和它对应的HR图像的重建效果,几乎看不出差异:

推理

顺序优化区块

  论文的推理策略是按顺序重建SR图像的各个区块,同时约束相邻区块的重叠部分的相似性。定义LR图像相邻区块之间的重叠为1像素宽,则相应SR图像相邻区块之间有4像素宽的重叠,并且图像能分成21x21个区块。则$(5)$式各个变量的规模如下

\begin{equation} \left\{ \begin{aligned} &\alpha_{ij}\in R^{2560\times 1},\;\;i,j=1,2,...,21\\ &p_{ij}\in R^{(4\times 4\times 3) \times 1},\;\;i,j=1,2,...,21\\ &D_l\in R^{(4\times 4\times 3) \times2560}\\ &D_h\in R^{(16\times 16\times 3) \times 2560}\\ \end{aligned} \right. \end{equation}

  优化代码如下:

#%%
import torch
import matplotlib.pyplot as plt
from torch import optim
from torch import random 
from torch.nn import functional as F


path_lr = r'E:\DataSets\SRTest\TestImages\LR\0003.jpg'
path_hr = r'E:\DataSets\SRTest\TestImages\HR\0003.jpg'
img_lr = plt.imread(path_lr) 
img_hr = plt.imread(path_hr) 

Dl = torch.load('dictionaries/Dic_LR').reshape([4,4,3,2560])
Dh = torch.load('dictionaries/Dic_HR').reshape([16,16,3,2560])   
def img_SR(LR_img, lambda1=0.5,lambda2=1,lambda3=1,lambda4=1,epoch=100):
  '''
  LR_img取值须在[0,255],形状为[64,64,3]
  ''' 
  LR_img = torch.tensor(LR_img,device='cuda',requires_grad=False) 
  SR_img = torch.zeros([256,256,3],device='cuda',requires_grad=False) 
  
  alpha_array = [] 
  for i in range(21):
    al = []
    for j in range(21): 
      al.append(torch.normal(0,1,[2560],device='cuda',requires_grad=True)) 
    alpha_array.append(al)
  
  def SRcompat_loss(patch, i, j):
    loss = 0
    if i > 0:
      loss += torch.mean(torch.abs(SR_img[12*i:12*i+4,12*j:12*j+16] - patch[:4]))
    if j > 0:
      loss += torch.mean(torch.abs(SR_img[12*i:12*i+16,12*j:12*j+4] - patch[:,:4]))
    return loss

  #按顺序计算SR各个区块  
  for i in range(21):
    for j in range(21): 
      alpha = alpha_array[i][j]
      opt = optim.RMSprop([alpha])
      for k in range(1, epoch): 
        L1 = torch.mean(torch.abs(alpha))
        L2 = torch.mean(torch.abs(torch.matmul(Dl,alpha) - LR_img[i*3:i*3+4,j*3:j*3+4]))
        L3 = SRcompat_loss(torch.matmul(Dh,alpha), i, j)
        down_SR = F.interpolate(torch.matmul(Dh,alpha).reshape([1,16,16,3]).permute([0,3,1,2]),size=[4,4], mode='bicubic')
        L4 = torch.mean(torch.abs(down_SR[0].permute([1,2,0]) - LR_img[i*3:i*3+4,j*3:j*3+4]))#额外的下采样一致性
        Loss = lambda1 * L1 + lambda2 * L2 + lambda3 * L3 + lambda4 * L4
        if k%800 ==0:
          print(k,Loss)
          for l in opt.param_groups:  
            l['lr'] *= 0.5
        opt.zero_grad()
        Loss.backward()
        opt.step()
        if Loss < 5:
          print(k,Loss)
          break 
      SR_img[12*i:12*i+16,12*j:12*j+16] = torch.matmul(Dh,alpha).detach()
    plt.imshow(SR_img.detach().cpu()/255)
    plt.show()
  return SR_img

img_sr = img_SR(img_lr,0.01,1,1,1,5000).cpu()/255   
fig = plt.figure(figsize=(15,15))
ax1,ax2,ax3 = fig.add_subplot(131),fig.add_subplot(132),fig.add_subplot(133)
ax1.imshow(img_lr),ax1.set_title('LR',fontsize=20)
ax2.imshow(img_sr),ax2.set_title('SR',fontsize=20)
ax3.imshow(img_hr),ax3.set_title('HR',fontsize=20)
plt.show()

  迭代了好久,结果如下:

  噪声很多,原因应该就是没有用论文中提到的使用反向投影法进行精炼,以及使用$F$操作吧。

另一种推理方式

  由于上述优化有先后顺序,后面的区块可能会损失精读来“迁就”前面已获得的SR区块,让重叠部分一致。因此论文在完成这一步后又加了一个全局一致性的约束,来调整已获得的SR图像,就是用所谓的反向投影法,但是写得很不明白。因此,我试验了一种直接对所有区块同时进行优化的方法。

  首先定义LR图像相邻区块的重叠为2像素宽,也就是4x4区块的一半。则相应的SR图像的相邻区块重叠为8像素宽,同样占其区块的一半。如此一来,SR相邻区块的兼容性可以通过创建两个“补丁”图来约束,如下图所示:

  即同时优化三个SR图像,第一张是最终的SR结果$x$,第二张用于约束$x$横向相邻区块之间的匹配度,第三张用于约束$x$纵向相邻区块之间的匹配度。也就是说,第一张图像相邻区块各取一半拼接成的图块要与第二、三图像中对应的区块一致。

  综上,对于测试LR图像$y$,分别去掉左右、上下边缘的2像素宽、高的图块,获得用于匹配约束的$y_r,y_c$。然后分别定义相应的表示$\alpha,\alpha_r,\alpha_c$。根据以上定义,各个参数的规模如下(LR图像区块被展开为向量的形式):

\begin{equation} \left\{ \begin{aligned} &\alpha\in R^{2560\times (16\times 16)}\\ &\alpha_r\in R^{2560\times (16\times 15)}\\ &\alpha_c\in R^{2560\times (15\times 16)}\\ &y\in R^{(4\times 4\times 3) \times(16\times 16)}\\ &y_r\in R^{(4\times 4\times 3) \times(16\times 15)}\\ &y_c\in R^{(4\times 4\times 3) \times(15\times 16)}\\ &D_l\in R^{(4\times 4\times 3) \times2560}\\ &D_h\in R^{(16\times 16\times 3) \times 2560}\\ \end{aligned} \right. \end{equation}

  则稀疏性约束、重建一致性约束、区块匹配度约束和最终的优化式如下:

\begin{equation} \begin{aligned} &L_{spars} = \|\alpha\|_1+\|\alpha_r\|_1+\|\alpha_c\|_1  \\ &L_{recon} = \|D_l\alpha - y\|_1+\|D_l\alpha_r - y_r\|_1+\|D_l\alpha_c - y_c\|_1 \\ &L_{comp} = \|P_1D_h\alpha - D_h\alpha_r\|_1+\|P_2D_h\alpha - D_h\alpha_c\|_1\\ &\min\limits_{\alpha,\alpha_r,\alpha_c}Loss =  \lambda_1 L_{spars}+\lambda_2L_{recon}+\lambda_3L_{comp} \end{aligned} \end{equation}

  $P_1,P_2$表示将SR图像映射到相应的匹配约束图像的操作,$\lambda_1,\lambda_2,\lambda_3$用于平衡三个约束的占比。使用$L1$范数是因为它能生成噪声更少的图像。另外,为了防止梯度过大,代码中计算的各项范数会除以元素数量,公式中没有标明。代码如下:

#%%
import torch
import matplotlib.pyplot as plt
from torch import optim
from torch.utils.tensorboard import SummaryWriter 


path_lr = r'E:\DataSets\SRTest\TestImages\LR\0003.jpg'
path_hr = r'E:\DataSets\SRTest\TestImages\HR\0003.jpg'
img_lr = plt.imread(path_lr) 
img_hr = plt.imread(path_hr) 

Dl = torch.load('dictionaries/Dic_LR')
Dh = torch.load('dictionaries/Dic_HR')
def img_SR(LR_img, lambda1=0.5,lambda2=1,lambda3=1,epoch=100):
  '''
  LR_img取值须在[0,255],形状为[64,64,3]
  ''' 
  LR_img = torch.tensor(LR_img,device='cuda',dtype=torch.float32)  
  LR_img_r = LR_img[:,2:-2]
  LR_img_c = LR_img[2:-2,:] 
  def img2patches(img):  
    patch_r = int(img.shape[0]/4)
    patch_c = int(img.shape[1]/4)
    patches = torch.zeros([4*4*3, patch_r*patch_c],device='cuda') 
    for i in range(patch_r): 
      for j in range(patch_c): 
        patches[:,i * patch_c + j] = torch.flatten(img[i*4:(i+1)*4,j*4:(j+1)*4])  
    return patches
  def patches2img(patches,row,col,ps=16):
    img = torch.zeros([row*ps, col*ps, 3],device='cuda')
    for i in range(row):
      for j in range(col):
        img[i*ps:(i+1)*ps, j*ps:(j+1)*ps] = patches[:,i*col+j].reshape([ps,ps,3])
    return img
   
  alpha = torch.normal(0,1,[2560,16*16],requires_grad=True,device='cuda') 
  alpha_r = torch.normal(0,1,[2560,16*15],requires_grad=True,device='cuda') 
  alpha_c = torch.normal(0,1,[2560,15*16],requires_grad=True,device='cuda') 
  y = img2patches(LR_img)
  y_r = img2patches(LR_img_r)
  y_c = img2patches(LR_img_c) 
 
  opt = optim.RMSprop([alpha,alpha_r,alpha_c])

  writer = SummaryWriter('InferLogs2/')
  for i in range(1, epoch):
    l_alpha = torch.mean(torch.abs(alpha))
    l_alpha_r = torch.mean(torch.abs(alpha_r))
    l_alpha_c = torch.mean(torch.abs(alpha_c))
    L1 = l_alpha + l_alpha_r + l_alpha_c

    l_rec1 = torch.mean(torch.abs(torch.matmul(Dl,alpha)-y))
    l_rec2 = torch.mean(torch.abs(torch.matmul(Dl,alpha_r)-y_r))
    l_rec3 = torch.mean(torch.abs(torch.matmul(Dl,alpha_c)-y_c))
    L2 = l_rec1 + l_rec2 + l_rec3

    l_comp1 = torch.mean(torch.abs(patches2img(torch.matmul(Dh,alpha),16,16,16)[:,8:-8] - patches2img(torch.matmul(Dh,alpha_r),16,15,16)))
    l_comp2 = torch.mean(torch.abs(patches2img(torch.matmul(Dh,alpha),16,16,16)[8:-8,:] - patches2img(torch.matmul(Dh,alpha_c),15,16,16)))
    L3 = l_comp1 + l_comp2

    Loss = lambda1 * L1 + lambda2 * L2 + lambda3 * L3

    opt.zero_grad()
    Loss.backward()
    opt.step()

    writer.add_scalar('L1',L1,i)
    writer.add_scalar('L2',L2,i)
    writer.add_scalar('L3',L3,i)
    writer.add_scalar('Loss',Loss,i)
    if i % 50 == 0:
      print(i, Loss)
      plt.imshow(patches2img(torch.matmul(Dh,alpha),16,16,16).detach().cpu()/255)
      plt.show()
      plt.imshow(patches2img(torch.matmul(Dl,alpha),16,16,4).detach().cpu()/255)
      plt.show()
    if i % 300 == 0:
      for i in opt.param_groups:
        i['lr'] *= 0.5 

  return patches2img(torch.matmul(Dl,alpha),16,16,4),patches2img(torch.matmul(Dh,alpha),16,16,16)
recon_LR_img,SR_img = img_SR(img_lr,100,1,1,epoch=1500) 
fig = plt.figure(figsize=(15,15))
ax1,ax2,ax3,ax4 = fig.add_subplot(221),fig.add_subplot(222),fig.add_subplot(223),fig.add_subplot(224)
ax1.imshow(recon_LR_img.detach().cpu()/255),ax1.set_title('Reconstructed LR',fontsize=20)
ax2.imshow(SR_img.detach().cpu()/255),ax2.set_title('SR',fontsize=20)
ax3.imshow(img_lr),ax3.set_title('LR',fontsize=20)
ax4.imshow(img_hr),ax4.set_title('HR',fontsize=20)
plt.show()

  不过实际效果也并不是很好:

总结

  综上,单纯使用稀疏表示做SR效果并不如人意。因为论文中还加了其它的方式和技巧来减少重建图像的噪声,而我这个实验没有加入,并且,论文的实验是放大3倍,区块大小为3x3,我这里与其并不相同,所以没能重现出论文的效果。另外,还可能是优化算法的缘故,论文使用的是凸优化(可能有某种方式算出解析解,但我看到L1范数就放弃了),我则是梯度下降。

  主要还是不想再做了。。。论文作者没有给出源代码,自己敲代码加写博客用了4天时间,想看其它论文了。

论文地址

  Image Super-Resolution via Sparse Representation

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Image Super-Resolution via Sparse Representation——基于稀疏表示的超分辨率重建 的相关文章

  • Spark 请求最大计数

    我是 Spark 的初学者 我尝试请求允许我检索最常访问的网页 我的要求如下 mostPopularWebPageDF logDF groupBy webPage agg functions count webPage alias cntW
  • python future 和元组解包

    实现像使用 future 进行元组解包这样的事情的优雅 惯用的方法是什么 我有这样的代码 a b c f x y g a b z h y c 我想将其转换为使用期货 理想情况下我想写一些类似的东西 a b c ex submit f x y
  • 如何正确地将 MIDI 刻度转换为毫秒?

    我正在尝试将 MIDI 刻度 增量时间转换为毫秒 并且已经找到了一些有用的资源 MIDI Delta 时间刻度到秒 http www lastrayofhope co uk 2009 12 23 midi delta time ticks
  • python 模拟第三方模块

    我正在尝试测试一些处理推文的类 我使用 Sixohsix twitter 来处理 Twitter API 我有一个类充当 Twitter 类的外观 我的想法是模拟实际的 Sixohsix 类 通过随机生成新推文或从数据库检索它们来模拟推文的
  • 从 ffmpeg 获取实时输出以在进度条中使用(PyQt4,stdout)

    我已经查看了很多问题 但仍然无法完全弄清楚 我正在使用 PyQt 并且希望能够运行ffmpeg i file mp4 file avi并获取流式输出 以便我可以创建进度条 我看过这些问题 ffmpeg可以显示进度条吗 https stack
  • 如何使用 imaplib 获取“消息 ID”

    我尝试获取一个在操作期间不会更改的唯一 ID 我觉得UID不好 所以我认为 Message ID 是正确的 但我不知道如何获取它 我只知道 imap fetch uid XXXX 有人有解决方案吗 来自 IMAP 文档本身 IMAP4消息号
  • 忽略 Mercurial hook 中的某些 Mercurial 命令

    我有一个像这样的善变钩子 hooks pretxncommit myhook python path to file myhook 代码如下所示 def myhook ui repo kwargs do some stuff 但在我的例子中
  • Pandas 数据帧到 numpy 数组 [重复]

    这个问题在这里已经有答案了 我对 Python 很陌生 经验也很少 我已经设法通过复制 粘贴和替换我拥有的数据来使一些代码正常工作 但是我一直在寻找如何从数据框中选择数据 但无法理解这些示例并替换我自己的数据 总体目标 如果有人真的可以帮助
  • 以同步方式使用 FastAPI,如何获取 POST 请求的原始正文?

    在中使用 FastAPIsync not async模式 我希望能够接收 POST 请求的原始 未更改的正文 我能找到的所有例子都显示async代码 当我以正常同步方式尝试时 request body 显示为协程对象 当我通过发布一些内容来
  • 在Python中调整图像大小

    我有一张尺寸为 288 352 的图像 我想将其大小调整为 160 240 我尝试了以下代码 im imread abc png img im resize 160 240 Image ANTIALIAS 但它给出了一个错误TypeErro
  • 如何通过在 Python 3.x 上按键来启动和中断循环

    我有这段代码 当按下 P 键时会中断循环 但除非我按下非 P 键 否则循环不会工作 def main openGame while True purchase imageGrab if a sum gt 1200 fleaButton ti
  • TensorFlow的./configure在哪里以及如何启用GPU支持?

    在我的 Ubuntu 上安装 TensorFlow 时 我想将 GPU 与 CUDA 结合使用 但我却停在了这一步官方教程 http www tensorflow org get started os setup md 这到底是哪里 con
  • 首先对列表中最长的项目进行排序

    我正在使用 lambda 来修改排序的行为 sorted list key lambda item item lower len item 对包含元素的列表进行排序A1 A2 A3 A B1 B2 B3 B 结果是A A1 A2 A3 B
  • 在 pytube3 中获取 youtube 视频的标题?

    我正在尝试构建一个应用程序来使用 python 下载 YouTube 视频pytube3 但我无法检索视频的标题 这是我的代码 from pytube import YouTube yt YouTube link print yt titl
  • 如何使用列表作为pandas数据框中的值?

    我有一个数据框 需要列的子集包含具有多个值的条目 下面是一个带有 运行时 列的数据框 其中包含程序在各种条件下的运行时 df condition a runtimes 1 1 5 2 condition b runtimes 0 5 0 7
  • 无法在 osx-arm64 上安装 Python 3.7

    我正在尝试使用 Conda 创建一个带有 Python 3 7 的新环境 例如 conda create n qnn python 3 7 我收到以下错误 Collecting package metadata current repoda
  • 使用yield 进行字典理解

    作为一个人为的例子 myset set a b c d mydict item yield join item s for item in myset and list mydict gives as cs bs ds a None b N
  • Elastic Beanstalk 中的 enum34 问题

    我正在尝试在 Elastic Beanstalk 中设置 django 环境 当我尝试通过requirements txt 文件安装时 我遇到了python3 6 问题 File opt python run venv bin pip li
  • Python 无法使用套接字绑定我的外部/公共 IP 地址,给出错误但是当使用本地 IP 地址时,错误不会显示

    这是出现主要错误的代码 与我的本地 IP 的绑定将起作用 s bind 192 168 1 4 port 与我的公共 IP 的绑定失败并出现以下错误 s bind 99 99 99 99 port WinError 10049 请求的地址在
  • 从 Twitter API 2.0 获取 user.fields 时出现问题

    我想从 Twitter API 2 0 端点加载推文 并尝试获取标准字段 作者 文本 和一些扩展字段 尤其是 用户 字段 端点和参数的定义工作没有错误 在生成的 json 中 我只找到标准字段 但没有找到所需的 user fields 用户

随机推荐

  • js 文字超出长度用省略号代替,鼠标悬停并以悬浮框显示

    题目中问题一拆为二 文字在超出长度时 如何实现用省略号代替 超长长度的文字在省略显示后 如何在鼠标悬停时 以悬浮框的形式显示出全部信息 文字在超出长度时 如何实现用省略号代替 用CSS实现超长字段用省略号表示的方法 所有浏览器兼容 html
  • 环境配置:Win10 - VSCode - MinGW64 - OpenCV 4.5.0 - ZBar 0.23.92

    环境配置 Win10 VSCode MinGW64 OpenCV 4 5 0 ZBar 0 23 92 前言 1 VSCode 下载VSCode 安装 C C 插件 项目配置 2 MinGW 选择MinGW的原因 MinGW下载 开始安装
  • 删除了文件,磁盘空间没有释放,怎么办

    find home type f size 1024M 先找出大于1G的文件 再lsof grep file看文件被哪个进程占用 再kill掉进程 再删除文件
  • 【论文导读】Causal Machine Learning:A Survey and Open Problems

    最新的arXiv上的综述 迅速过一遍 2022 7 13 历史 C1已看完 三页 ML面临挑战 1 当数据分布发生变化时 泛化性能大幅下降 2 缺乏对生成模型样本的精细控制 3 有偏见的预测加强了对某些子群体的不公平歧视 4 过度抽象和与问
  • 怎么往服务器里拷贝文件,怎么往云服务器上拷贝文件

    怎么往云服务器上拷贝文件 内容精选 换一换 无法直接从云备份控制台查看备份中的数据 您可以通过以下几种方式进行查看 云服务器备份使用云服务器备份创建镜像后 再使用镜像创建云服务器 登录云服务器 查看服务器中的数据 云硬盘备份使用云硬盘备份创
  • mysql5.7递归查询

    MySQL 5 7支持递归查询 这种查询方式可以在一个表中查找具有父子关系的数据 递归查询通常使用WITH RECURSIVE语句进行构造 这个语句使用两个部分 递归部分和终止部分 递归部分定义了递归查询的开始条件和递归关系 而终止部分定义
  • LVGL使用记 - 数据更新显示

    介绍一下界面数据显示方法 关键API Set a an event handler function for an object Used by the user to react on event which happens with t
  • 数字藏品源码APP商城开发团队

    数字藏品源码APP商城开发团队 数字藏品商城软件开发 数字藏品分销模式开发 数字藏品交易平台开发 数字藏品现成源码软件定制 微信分销返利制度开发 NFT数字藏品平台开发定制 数字藏品系统多少钱 在全世界范围来看 数字藏品的外延更大 通常被称
  • flea-db使用之SQL模板接入

    SQL模板接入 引言 1 准备工作 2 使用讲解 2 1 SQL模板配置 2 2 新增数据 2 3 查询数据 2 4 更新数据 2 5 删除数据 2 6 分页查询 2 7 单个结果查询 计数 2 8 单个结果查询 总和 引言 本篇将要演示
  • 2017-7-28 2-8 编写函数rightrot(x,n),该函数返回将x循环右移(即从最右端移出的位将从最左端移入)n位后所得到的值

    include
  • Prefix Flip【小模拟】

    题目链接CF 1382 C2 题意 有两个字符串 现在我们要让第一个字符串变成第二个字符串 只允许使用2N次操作 问操作 每次操作是选前缀x个 然后首先前缀x全体异或1 然后字符串翻转 于是 很明显的 我们可以按次数每次维护最后一个字符串
  • Python 字符串与二进制串的相互转换

    一个问题 在Python中 如何将一个字符串转换为相应的二进制串 01形式表示 并且能够将这个二进制串再转换回原来的字符串 一个简单版本 def encode s return join bin ord c replace 0b for c
  • 企业实施数字工厂管理系统应对这几个流程进行优化

    在当今快速发展的商业环境中 企业需要不断地提高管理水平以保持竞争优势 数字工厂系统解决方案作为一种先进的信息化管理系统 可以帮助企业在多个方面实现管理改进 本文将探讨数字工厂管理系统对企业管理的九个方面的影响和作用 一 企业信息化管理方面
  • iOS下XMPP开发之XMPP开发环境配置(一)MySQL安装配置

    1 即时通讯技术简介 即时通讯技术 IM Instant Messaging 支持用户在线实时交谈 如果要发送一条信息 用户需要打开一个小窗口 以便让用户及其朋友在其中输入信息并让交谈双方都看到交谈的内容 有许多的IM系统 如AOL Yah
  • 【Note】关于研发合作中spillover(溢出)的理解

    1 文献中的描述 1 1 technology spillover 其中非常重要的一点是 称之为technology spillover 技术溢出 的部分直接影响的是成本 而不是其他的部分 效用之类的 意识到这个关键点之后 才理解了为什么很
  • Qt中静态变量使用方法

    静态变量可以在各个页面之前使用 先定义一个用于存放静态变量的类 例如datavar 在datavar h中添加如下代码 ifndef DATAVAR H define DATAVAR H include
  • Mybatis3 快速入门

    Mybatis3 快速入门 目前常见的持久层java框架有Hibernate Mybatis SpringData 笔者比较喜欢用SpringData Hibernate 和 Mybatis 也经常用 今天通过 Mybatis 的简介 数据
  • js 中的document.open 方法

    转载自 http blog 163 com hanyan102600 126 blog static 438503422008228111841848 document open 定义和用法 open 方法可打开一个新文档 并擦除当前文档的
  • 聊一聊Cookie(结合自己的学习方法分享一篇维基百科和一篇segmentfault(思否)好文)

    一 最近在带着Java服务端同学一起做一个新的项目 有一些基本的概念 无论是前端还是Java服务端 很多同学都是在按照经验办事 在一个公司的经验用很多年 经常容易犯经验主义的错误 很多时候 最基础的概念 最基本的东西还是要懂的 二 首先学习
  • Image Super-Resolution via Sparse Representation——基于稀疏表示的超分辨率重建

    经典超分辨率重建论文 基于稀疏表示 下面首先介绍稀疏表示 然后介绍论文的基本思想和算法优化过程 最后使用python进行实验 稀疏表示 稀疏表示是指 使用过完备字典中少量向量的线性组合来表示某个元素 过完备字典是一个列数大于行数的行满秩矩阵