jjzjj

GAN综述及其在图像生成领域的应用(含原理、代码详解)

蓝鲸鱼BlueWhale 2023-04-04 原文

本文将持续更新。

目录

1. 基本GAN

1.1 GAN(2014)

原始GAN由生成器 G G G和判别器 D D D构成,生成器的目的就是将随机输入的高斯噪声映射成图像(“假图”),判别器则是判断输入图像是否来自生成器的概率,即判断输入图像是否为假图的概率。

GAN的训练是个动态的过程,是生成器 G G G与判别器 D D D两者之间的相互博弈过程。生成器G要生成假图骗过判别器 D D D,而判别器 D D D要分辨生成器 G G G生成的假图。GAN的损失函数如下:


其中, G G G代表生成器, D D D代表判别器, x x x代表真实数据, p d a t a p_{data} pdata代表真实数据概率密度分布, z z z代表了随机输入数据,该数据是随机高斯噪声。

从上式可以看出,从判别器 D D D角度来看,判别器 D D D希望能尽可能区分真实样本x和虚假样本 G ( z ) G(z) G(z) ,因此 D ( x ) D(x) D(x)必须尽可能大, D ( G ( z ) ) D(G(z)) D(G(z))尽可能小, 也就是 V ( D , G ) V(D,G) V(D,G)整体尽可能大。从生成器 G G G的角度来看,生成器 G G G希望自己生成的虚假数据 G ( z ) G(z) G(z)可以尽可能骗过判别器 D D D,也就是希望 D ( G ( z ) ) D(G(z)) D(G(z))尽可能大,也就是 V ( D , G ) V(D,G) V(D,G)整体尽可能小。GAN的两个模块在训练相互对抗,最后达到全局最优。图源。


训练过程的代码示例如下。

for epoch in range(opt.n_epochs):
    for i, (imgs, _) in enumerate(dataloader):

        # Adversarial ground truths
        valid = Variable(Tensor(imgs.size(0), 1).fill_(1.0), requires_grad=False)
        fake = Variable(Tensor(imgs.size(0), 1).fill_(0.0), requires_grad=False)

        # Configure input
        real_imgs = Variable(imgs.type(Tensor))

        # -----------------
        #  Train Generator
        # -----------------

        optimizer_G.zero_grad()

        # Sample noise as generator input
        z = Variable(Tensor(np.random.normal(0, 1, (imgs.shape[0], opt.latent_dim))))

        # Generate a batch of images
        gen_imgs = generator(z)

        # Loss measures generator's ability to fool the discriminator
        g_loss = adversarial_loss(discriminator(gen_imgs), valid)

        g_loss.backward()
        optimizer_G.step()

        # ---------------------
        #  Train Discriminator
        # ---------------------

        optimizer_D.zero_grad()

        # Measure discriminator's ability to classify real from generated samples
        real_loss = adversarial_loss(discriminator(real_imgs), valid)
        fake_loss = adversarial_loss(discriminator(gen_imgs.detach()), fake)
        d_loss = (real_loss + fake_loss) / 2

        d_loss.backward()
        optimizer_D.step()

1.2 CGAN(2015)

CGAN的主要贡献是在原始GAN的生成器与判别器中的输入中加入额外标签信息 y y y。额外信息 y y y可以是任何信息,主要是标签。因此CGAN的提出使得GAN可以利用图像与对应的标签进行训练,并在测试阶段利用给定标签生成特定图像。其损失函数如下:

在CGAN的论文中,网络架构使用的MLP(全连接网络)。在CGAN中的生成器,我们给定一个输入噪声 p z ( z ) p_z(z) pz(z)和额外信息 y y y,之后将两者通过全连接层连接到一起,作为隐藏层输入。同样地,在判别器中输入图像 x x x和 额外信息 y y y也将连接到一起作为隐藏层输入。

CGAN和GAN的区别如下:

for epoch in range(opt.n_epochs):
    for i, (imgs, labels) in enumerate(dataloader):
    
        # define labels and gen_labbels:
        labels = Variable(labels.type(LongTensor))
        gen_labels = Variable(LongTensor(np.random.randint(0, opt.n_classes, batch_size)))

        # -----------------
        #  Train Generator
        # -----------------
        
        # input + genlabels
        gen_imgs = generator(z, gen_labels)
        validity = discriminator(gen_imgs, gen_labels)
        
        # ---------------------
        #  Train Discriminator
        # ---------------------
        
        # input + labels or genlabels
        validity_real = discriminator(real_imgs, labels)
        validity_fake = discriminator(gen_imgs.detach(), gen_labels)

1.3 DCGAN(2015)

DCGAN主要是在网络架构上改进了原始GAN,DCGAN的生成器与判别器都利用CNN架构替换了原始GAN的全连接网络,主要改进之处有如下几个方面:

  1. DCGAN的生成器和判别器都舍弃了CNN的池化层,判别器保留CNN的整体架构,生成器则是将卷积层替换成了反卷积层(或称转置卷积层)。
  2. 在判别器和生成器中在每一层之后都是用了BN层,有助于处理初始化不良导致的训练问题,加速模型训练,提升了训练的稳定性。
  3. 利用1*1卷积层替换到所有的全连接层。
  4. 在生成器中除输出层使用Sigmoid激活函数,其余层全部使用ReLu激活函数。
  5. 在判别器所有层都使用LeakyReLU激活函数,防止梯度稀疏。

1.4 VAE-GAN(2016)

变分自编码器VAE是由一个编码器和一个解码器组成的结构,编码器可以将数据映射到一个低维的空间分布,而解码器可以将这个分布还原回原始数据,因此解码器是很像GAN中的生成器。VAE的目的也和GAN相似,都是希望构建一个从隐变量 z z z生成目标数据 x x x的模型。

如果在VAE后面拼接上一个判别器D,这样的话,前两个模块就是VAE,后两个模块就是GAN:


从VAE的角度,VAE解码产生的图片往往都比较模糊,GAN中的判别器来判别图片是不是真实的,可以来帮助VAE提高真实性。从GAN的角度,原本生成器输入都是随机的,训练起来比较难,而VAE可以提供生成器输入的大概空间分布,会变得准确高效一些。因此VAE和GAN相辅相成,都可达到更优秀的效果。

1.5 ACGAN(2017)

为了提供更多的辅助信息并允许半监督学习,可以向判别器添加额外的辅助分类器,以便在原始任务以及附加任务上优化模型。这种方法的体系结构如下图所示,其中C是辅助分类器。 添加辅助分类器允许我们使用预先训练的模型(例如,在ImageNet上训练的图像分类器)。


ACGAN和CGAN的代码的区别如下,在辨别器D中增加adv层和aux层,用来计算Label:

class Discriminator(nn.Module):
    def __init__(self):
    	self.conv_blocks = ...
        self.adv_layer = nn.Sequential(nn.Linear(128 * ds_size ** 2, 1), nn.Sigmoid())
        self.aux_layer = nn.Sequential(nn.Linear(128 * ds_size ** 2, opt.n_classes), nn.Softmax())

    def forward(self, img):
        out = self.conv_blocks(img)
        out = out.view(out.shape[0], -1)
        validity = self.adv_layer(out)
        label = self.aux_layer(out)
        return validity, label

for epoch in range(opt.n_epochs):
    for i, (imgs, labels) in enumerate(dataloader):
        # -----------------
        #  Train Generator
        # -----------------

        # output the pred_label and add auxiliary_loss
        validity, pred_label = discriminator(gen_imgs)
        g_loss = 0.5 * (adversarial_loss(validity, valid) + auxiliary_loss(pred_label, gen_labels))
        
        # ---------------------
        #  Train Discriminator
        # ---------------------
        
        # Loss for real images
        real_pred, real_aux = discriminator(real_imgs)
        d_real_loss = (adversarial_loss(real_pred, valid) + auxiliary_loss(real_aux, labels)) / 2

        # Loss for fake images
        fake_pred, fake_aux = discriminator(gen_imgs.detach())
        d_fake_loss = (adversarial_loss(fake_pred, fake) + auxiliary_loss(fake_aux, gen_labels)) / 2

        # Total discriminator loss
        d_loss = (d_real_loss + d_fake_loss) / 2

        # Calculate discriminator accuracy
        pred = np.concatenate([real_aux.data.cpu().numpy(), fake_aux.data.cpu().numpy()], axis=0)
        gt = np.concatenate([labels.data.cpu().numpy(), gen_labels.data.cpu().numpy()], axis=0)
        d_acc = np.mean(np.argmax(pred, axis=1) == gt)

1.6 styleGAN(2018)

StyleGAN也可以算作图像生成领域的应用,但是由于它主要改变网络结构,因此我们将它归类于第一章。

StyleGAN提出了一个新的生成器结构如下:


不同于以往的GAN论文把 z z z输入给生成器的输入层的做法,StyleGAN在生成器各层都注入噪音,且摒弃了输入层, 转而添加了一个从 Z Z Z W W W的非线性映射网络,将输入 z z z用了8层全连接层做了个非线性变换,得到 w w w

图中, Z Z Z W W W的维度都是512维, A A A是一个仿射变换, B B B是每个通道的高斯噪声的系数,而AdaIN则是:

图中, y s , i 和 y b , i y_{s,i}和y_{b,i} ys,iyb,i则是 w w w经过 A A A变换之后得到的style: y = ( y s , y b ) y=(y_s,y_b) y=(ys,yb) ( y s , i , y b , i ) (y_{s,i},y_{b,i}) (ys,i,yb,i)对的个数与每一层特征图的通道数相同,对应每一层归一化所需的scale和shift。

为进一步促使style局部化图像转换的控制效果,作者采用了mixing regularization。利用生成器中8层卷积的非线性变换,提前计算两个图像的变换结果 w 1 , w 2 w_1,w_2 w1,w2 ,然后在生成过程中随机取 w 1 w_1 w1 或者 w 2 w_2 w2 的值进行操作。结果如下,可以看到横轴和纵轴上的原始图像不同程度地影响了生成的图像。

2. GAN在图像生成领域的应用

2.1 Pix2Pix(2017)

Pix2Pix可以称之为用CGAN做image translation的鼻祖,先看一下他的效果:


训练大致过程如下:


我们将CGAN的结构放在下面以方便对比。可以看到,Pix2Pix采用CGAN的结构,将图片 x x x作为CGAN的条件(相当于是一个”鞋“的标签),输入到 G G G D D D中。 G G G的输入是 x , z {x,z} x,z(其中, x x x是需要转换的图片, z z z是随机噪声),输出是生成的图片 G ( x , z ) G(x,z) G(x,z) D D D则需要分辨出 x , G ( x , z ) {x,G(x,z)} x,G(x,z) x , y {x,y} x,y


Pix2Pix使用的生成器 G G G用到的是Unet结构,输入的轮廓图 x x x编码再解码成真是图片,判别器D用到的是作者自己提出来的条件判别器PatchGAN。损失函数如下:

  1. CGAN损失函数:
  2. 与ground truch的loss:
  3. 最终损失:

但是,Pix2Pix的一个限制在于网络学习的是 x x x y y y之间的一对一映射。这样的一个明显的缺点就是对数据集的限制:需要大量对应的图片,例如同一个地方的黑夜和白天的图片。

代码:

for epoch in range(opt.epoch, opt.n_epochs):
    for i, batch in enumerate(dataloader):

        # Model inputs, A is label
        real_A = Variable(batch["B"].type(Tensor))
        real_B = Variable(batch["A"].type(Tensor))

        # Adversarial ground truths
        valid = Variable(Tensor(np.ones((real_A.size(0), *patch))), requires_grad=False)
        fake = Variable(Tensor(np.zeros((real_A.size(0), *patch))), requires_grad=False)

        # ------------------
        #  Train Generators
        # ------------------

        optimizer_G.zero_grad()

        # GAN loss
        fake_B = generator(real_A)
        pred_fake = discriminator(fake_B, real_A)
        loss_GAN = criterion_GAN(pred_fake, valid)
        
        # Pixel-wise loss
        loss_pixel = criterion_pixelwise(fake_B, real_B)

        # Total loss
        loss_G = loss_GAN + lambda_pixel * loss_pixel

        loss_G.backward()

        optimizer_G.step()

        # ---------------------
        #  Train Discriminator
        # ---------------------
		# same process as CGAN

2.2 cycleGAN(2017)

相比于Pix2Pix需要两个域中有相同数据的训练样本。CycleGAN的创新点在于能够在源域和目标域之间,无须建立训练数据间一对一的映射,就可实现这种迁移,效果如下:


CycleGAN由两个判别器( D x D_x Dx D y D_y Dy)和两个生成器( G G G F F F)组成,生成器 G G G F F F分别是 X X X Y Y Y Y Y Y X X X的映射,两个判别器 D x D_x Dx D y D_y Dy对转换后的图片进行判别。双判别器的目的是为了建立一对一的映射,避免所有的 X X X都被映射到同一个 Y Y Y,例如所有男人的图像都映射到刘亦菲的图像上。起到同样作用的是cycle-consistency loss,用数据集中其他的图来检验生成器,防止 G G G F F F过拟合。


CycleGAN的训练过程如下,两张图分别表示从 X X X域到 Y Y Y域的图像生成和从 Y Y Y域到 X X X域的图像生成。其中Input_A表示输入的真实图像,Generated_B表示由表示由Input_A转换得到的图像,Cyclic_A表示由Input_A转换一圈得到的图像。反之亦然。图源



损失函数包含:

  1. 对抗损失函数

    以及对偶的
  2. Cycle Consistency 损失
  3. 总损失

代码如下:

# Losses
criterion_GAN = torch.nn.MSELoss()
criterion_cycle = torch.nn.L1Loss()
criterion_identity = torch.nn.L1Loss()

for epoch in range(opt.epoch, opt.n_epochs):
    for i, batch in enumerate(dataloader):

        # Set model input
        real_A = Variable(batch["A"].type(Tensor))
        real_B = Variable(batch["B"].type(Tensor))

        # Adversarial ground truths
        valid = Variable(Tensor(np.ones((real_A.size(0), *D_A.output_shape))), requires_grad=False)
        fake = Variable(Tensor(np.zeros((real_A.size(0), *D_A.output_shape))), requires_grad=False)

        # ------------------
        #  Train Generators
        # ------------------

        G_AB.train()
        G_BA.train()

        optimizer_G.zero_grad()

        # Identity loss
        loss_id_A = criterion_identity(G_BA(real_A), real_A)
        loss_id_B = criterion_identity(G_AB(real_B), real_B)

        loss_identity = (loss_id_A + loss_id_B) / 2

        # GAN loss
        fake_B = G_AB(real_A)
        loss_GAN_AB = criterion_GAN(D_B(fake_B), valid)
        fake_A = G_BA(real_B)
        loss_GAN_BA = criterion_GAN(D_A(fake_A), valid)

        loss_GAN = (loss_GAN_AB + loss_GAN_BA) / 2

        # Cycle loss
        recov_A = G_BA(fake_B)
        loss_cycle_A = criterion_cycle(recov_A, real_A)
        recov_B = G_AB(fake_A)
        loss_cycle_B = criterion_cycle(recov_B, real_B)

        loss_cycle = (loss_cycle_A + loss_cycle_B) / 2

        # Total loss
        loss_G = loss_GAN + opt.lambda_cyc * loss_cycle + opt.lambda_id * loss_identity

        loss_G.backward()
        optimizer_G.step()

        # -----------------------
        #  Train Discriminator A
        # -----------------------

        optimizer_D_A.zero_grad()

        # Real loss
        loss_real = criterion_GAN(D_A(real_A), valid)
        # Fake loss (on batch of previously generated samples)
        fake_A_ = fake_A_buffer.push_and_pop(fake_A)
        loss_fake = criterion_GAN(D_A(fake_A_.detach()), fake)
        # Total loss
        loss_D_A = (loss_real + loss_fake) / 2

        loss_D_A.backward()
        optimizer_D_A.step()

        # -----------------------
        #  Train Discriminator B
        # -----------------------

        optimizer_D_B.zero_grad()

        # Real loss
        loss_real = criterion_GAN(D_B(real_B), valid)
        # Fake loss (on batch of previously generated samples)
        fake_B_ = fake_B_buffer.push_and_pop(fake_B)
        loss_fake = criterion_GAN(D_B(fake_B_.detach()), fake)
        # Total loss
        loss_D_B = (loss_real + loss_fake) / 2

        loss_D_B.backward()
        optimizer_D_B.step()

        loss_D = (loss_D_A + loss_D_B) / 2

2.3 starGAN(2018)

Pix2Pix模型解决了paired数据的图像翻译问题;CycleGAN解决了Unpaired数据下的图像翻译问题,但它们都是单领域的转换,而StarGAN则应用于多领域,即在同一种模型下做多个图像翻译任务,效果如下:


如下图所示,当多领域转换时,对于每一个领域转换,如果都需要重新训练一个模型去解决,这样的行为就太低效了,而StarGAN将多领域转换用统一框架实现。


由于StarGAN时在多数据集下训练,而数据集之间有可能出现虽然类别不相交,但内容相交的情况。比如CelebA数据集合RaFD数据集,前者拥有肤色,年龄的类别。而后者拥有表情的类别。但前者的图像很多也是有表情的,这就导致前一类的图像在后一类的标记是不可知的。

为了解决这个问题,在模型输入中加入了Mask,即如果来源于数据集B,那么将数据集A中的标记全部设为0,示意图如下:

starGAN使用的损失函数如下:

  1. 对抗损失
  2. D分类损失,使用真实图像在原始领域进行
  3. G分类损失,使用生成图像在目标领域进行
  4. 重建函数,与CycleGAN类似
  5. 总损失

    代码如下。表示多领域的方法主要在于加入了sampled_c。
for epoch in range(opt.epoch, opt.n_epochs):
    for i, (imgs, labels) in enumerate(dataloader):

        # Sample labels as generator inputs
        sampled_c = Variable(Tensor(np.random.randint(0, 2, (imgs.size(0), c_dim))))
        # Generate fake batch of images
        fake_imgs = generator(imgs, sampled_c)

        # ---------------------
        #  Train Discriminator
        # ---------------------

        optimizer_D.zero_grad()

        # Real images
        real_validity, pred_cls = discriminator(imgs)
        # Fake images
        fake_validity, _ = discriminator(fake_imgs.detach())
        # Gradient penalty
        gradient_penalty = compute_gradient_penalty(discriminator, imgs.data, fake_imgs.data)
        # Adversarial loss
        loss_D_adv = -torch.mean(real_validity) + torch.mean(fake_validity) + lambda_gp * gradient_penalty
        # Classification loss
        loss_D_cls = criterion_cls(pred_cls, labels)
        # Total loss
        loss_D = loss_D_adv + lambda_cls * loss_D_cls

        loss_D.backward()
        optimizer_D.step()

        optimizer_G.zero_grad()

        # Every n_critic times update generator
        if i % opt.n_critic == 0:

            # -----------------
            #  Train Generator
            # -----------------

            # Translate and reconstruct image
            gen_imgs = generator(imgs, sampled_c)
            recov_imgs = generator(gen_imgs, labels)
            # Discriminator evaluates translated image
            fake_validity, pred_cls = discriminator(gen_imgs)
            # Adversarial loss
            loss_G_adv = -torch.mean(fake_validity)
            # Classification loss
            loss_G_cls = criterion_cls(pred_cls, sampled_c)
            # Reconstruction loss
            loss_G_rec = criterion_cycle(recov_imgs, imgs)
            # Total loss
            loss_G = loss_G_adv + lambda_cls * loss_G_cls + lambda_rec * loss_G_rec

            loss_G.backward()
            optimizer_G.step()

2.4 SPADE(2019)

SPADE又名GauGAN,可以根据用户画的简单图像得到合成的实际图像,在合成时用户还可以选择合成图像的风格,得到非常多样的合成结果,如下图所示。

SPADE通过语义分割图生成原始图像,作者发现将语义分割图直接作为生成网络的输入进行计算时,这些生成网络中常用的传统BN层容易丢失输入语义图像中的信息, 因此提出了新的归一化层Spatially-Adaptive Normalization(SAN)来解决这个问题。

SAN是在BN的基础上做了修改,修改内容就在于γ和β计算的不同,如下图所示。在BN中 γ γ γ β β β的计算是通过网络训练得到的,而SAN中γ和β是通过语义图像计算得到的。


SAN的计算过程如下。在BN中, γ γ γ β β β是向量一维的,其中每个值对应输入特征图的每个通道。而在SAN中, γ γ γ β β β是三维矩阵,除了通道维度外,还有宽和高维度,因此下式中 γ γ γ β β β下标包含 c , y , x c,y,x c,y,x三个符号,这也是spatially-adaptive的含义,翻译过来就是在空间上是有差异的,或者叫自适应的。而BN的 γ γ γ β β β的下标只有 c c c,也就是通道,这种不区分空间维度的计算方式就比较容易丢失输入图像的信息。


公式中的均值 μ μ μ和标准差 σ σ σ的计算如下,这部分和BN中的计算一样。

在网络结构方面,下图是SPADE算法中生成器的网络结构示意图,生成器采用堆叠多个SPADE ResBlk实现(右图),其中每个SPADE ResBlk的结构如左图所示,SAN层中的 γ γ γ β β β参数通过输入的语义图像计算得到。

关于SPADE算法是如何实现多样化输出的。下图是SPADE算法的整体示意图,生成器的输入是一个向量,这个向量可以是随机值,这样生成的图像也是随机的;同样,这个向量也可以通过一个编码网络和一张风格图像计算得到,编码网络将输入图像编码成向量,这个向量就包含输入图像的风格,这样就能得到多样化风格输出的效果了。

参考文献:

  1. An Introduction to Image Synthesis with Generative Adversarial Nets
  2. DCGAN论文详解
  3. GAN在图像生成应用综述(论文解读)
  4. 完整code
  5. [GAN笔记] pix2pix
  6. 生成对抗网络系列(4)——pix2pix
  7. 深度学习《VAE-GAN》
  8. Understanding and Implementing CycleGAN in TensorFlow
  9. CycleGAN原理以及代码全解析
  10. CycleGAN算法原理
  11. StarGAN-多领域图像翻译
  12. 论文阅读-人脸生成_StyleGAN
  13. SPADE(GauGAN)算法笔记

有关GAN综述及其在图像生成领域的应用(含原理、代码详解)的更多相关文章

  1. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

    我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

  2. ruby - 将差异补丁应用于字符串/文件 - 2

    对于具有离线功能的智能手机应用程序,我正在为Xml文件创建单向文本同步。我希望我的服务器将增量/差异(例如GNU差异补丁)发送到目标设备。这是计划:Time=0Server:hasversion_1ofXmlfile(~800kiB)Client:hasversion_1ofXmlfile(~800kiB)Time=1Server:hasversion_1andversion_2ofXmlfile(each~800kiB)computesdeltaoftheseversions(=patch)(~10kiB)sendspatchtoClient(~10kiBtransferred)Cl

  3. ruby - 如何在 buildr 项目中使用 Ruby 代码? - 2

    如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby​​

  4. ruby-on-rails - Rails 源代码 : initialize hash in a weird way? - 2

    在rails源中:https://github.com/rails/rails/blob/master/activesupport/lib/active_support/lazy_load_hooks.rb可以看到以下内容@load_hooks=Hash.new{|h,k|h[k]=[]}在IRB中,它只是初始化一个空哈希。和做有什么区别@load_hooks=Hash.new 最佳答案 查看rubydocumentationforHashnew→new_hashclicktotogglesourcenew(obj)→new_has

  5. ruby-on-rails - Rails 应用程序之间的通信 - 2

    我构建了两个需要相互通信和发送文件的Rails应用程序。例如,一个Rails应用程序会发送请求以查看其他应用程序数据库中的表。然后另一个应用程序将呈现该表的json并将其发回。我还希望一个应用程序将存储在其公共(public)目录中的文本文件发送到另一个应用程序的公共(public)目录。我从来没有做过这样的事情,所以我什至不知道从哪里开始。任何帮助,将不胜感激。谢谢! 最佳答案 无论Rails是什么,几乎所有Web应用程序都有您的要求,大多数现代Web应用程序都需要相互通信。但是有一个小小的理解需要你坚持下去,网站不应直接访问彼此

  6. ruby - 无法运行 Rails 2.x 应用程序 - 2

    我尝试运行2.x应用程序。我使用rvm并为此应用程序设置其他版本的ruby​​:$rvmuseree-1.8.7-head我尝试运行服务器,然后出现很多错误:$script/serverNOTE:Gem.source_indexisdeprecated,useSpecification.Itwillberemovedonorafter2011-11-01.Gem.source_indexcalledfrom/Users/serg/rails_projects_terminal/work_proj/spohelp/config/../vendor/rails/railties/lib/r

  7. ruby - 在 jRuby 中使用 'fork' 生成进程的替代方案? - 2

    在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',

  8. ruby-on-rails - Rails 应用程序中的 Rails : How are you using application_controller. rb 是新手吗? - 2

    刚入门rails,开始慢慢理解。有人可以解释或给我一些关于在application_controller中编码的好处或时间和原因的想法吗?有哪些用例。您如何为Rails应用程序使用应用程序Controller?我不想在那里放太多代码,因为据我了解,每个请求都会调用此Controller。这是真的? 最佳答案 ApplicationController实际上是您应用程序中的每个其他Controller都将从中继承的类(尽管这不是强制性的)。我同意不要用太多代码弄乱它并保持干净整洁的态度,尽管在某些情况下ApplicationContr

  9. ruby - 如何使用 Ruby aws/s3 Gem 生成安全 URL 以从 s3 下载文件 - 2

    我正在编写一个小脚本来定位aws存储桶中的特定文件,并创建一个临时验证的url以发送给同事。(理想情况下,这将创建类似于在控制台上右键单击存储桶中的文件并复制链接地址的结果)。我研究过回形针,它似乎不符合这个标准,但我可能只是不知道它的全部功能。我尝试了以下方法:defauthenticated_url(file_name,bucket)AWS::S3::S3Object.url_for(file_name,bucket,:secure=>true,:expires=>20*60)end产生这种类型的结果:...-1.amazonaws.com/file_path/file.zip.A

  10. ruby-on-rails - 如何在我的 Rails 应用程序 View 中打印 ruby​​ 变量的内容? - 2

    我是一个Rails初学者,但我想从我的RailsView(html.haml文件)中查看Ruby变量的内容。我试图在ruby​​中打印出变量(认为它会在终端中出现),但没有得到任何结果。有什么建议吗?我知道Rails调试器,但更喜欢使用inspect来打印我的变量。 最佳答案 您可以在View中使用puts方法将信息输出到服务器控制台。您应该能够在View中的任何位置使用Haml执行以下操作:-puts@my_variable.inspect 关于ruby-on-rails-如何在我的R

随机推荐