PyTorch-12 GAN、WGAN

2023-11-19

PyTorch-12 生成对抗网络(GAN 、WGAN)

参考:https://zhuanlan.zhihu.com/p/34287744
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
GAN模型的目标函数如下:
在这里插入图片描述

GAN模型优化训练

在训练过程中,生成网络的目标就是尽量生成真实的图片去欺骗判别网络D。而网络D的目标就是尽量把网络G生成的图片和真实的图片分别开来。这样,G和D构成了一个动态的“博弈过程”。这个博弈过程具体是怎么样的呢?

先了解下纳什均衡,纳什均衡是指博弈中这样的局面,对于每个参与者来说,只要其他人不改变策略,他就无法改善自己的状况。对应的,对于GAN,情况就是生成模型 G 恢复了训练数据的分布(造出了和真实数据一模一样的样本),判别模型再也判别不出来结果,准确率为 50%,约等于乱猜。这是双方网路都得到利益最大化,不再改变自己的策略,也就是不再更新自己的权重。

GAN模型的目标函数如下:
在这里插入图片描述
在这里,训练网络D使得最大概率地分对训练样本的标签(最大化log D(x)和 log(1 - D(G(z))) ),训练网络G最小化log(1 – D(G(z))),即最大化D的损失。而训练过程中固定一方,更新另一个网络的参数,交替迭代,使得对方的错误最大化,最终,G 能估测出样本数据的分布,也就是生成的样本更加的真实。

然后从式子中解释对抗,我们知道G网络的训练是希望[公式]趋近于1,也就是正类,这样G的loss就会最小。而D网络的训练就是一个2分类,目标是分清楚真实数据和生成数据,也就是希望真实数据的D输出趋近于1,而生成数据的输出即[公式]趋近于0,或是负类。这里就是体现了对抗的思想。

然后,这样对抗训练之后,效果可能有几个过程,原论文画出的图如下:
在这里插入图片描述

情况1:我们固定住G生成器,查看D判别器能够达到什么水平。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
结论:G生成器固定,D判别器的最大值为 Pr(x) /(Pr(x) + Pg(x))

情况2:在D判别器计算完成最大值后(也就是停止D判别器),开始计算G生成器最小值

KL Divergence V.S. JS Divergence
在这里插入图片描述
在这里插入图片描述
只要pr = pg的时候,Djs(pr || pg) = 0。
在这里插入图片描述
结论:在D判别器优化到最大值后,G生成器进化到最小程度为-2log2
前提是pr = pg时,也就是pg逼近pr,G生成器也达到最小。

当G生成器优化到最小值时,其pr=pg的,因此D判别器的最大值Pr(x) /(Pr(x) + Pg(x))= 1/2 = 0.5

DCGAN 深度卷积生成对抗网络

在这里插入图片描述
通过Transposed Convolution可以扩大图片的大小
在这里插入图片描述

The Last thing?

▪ Training Stability

Why?

在这里插入图片描述

Toy example

在这里插入图片描述

Toy example

在这里插入图片描述

JS Divergence

在这里插入图片描述

Gradient Vanishing 渐变消失

在这里插入图片描述

Training Progress Invisible 训练的进展是看不见的

Training Progress Indicator
在这里插入图片描述

HowTo

在这里插入图片描述

The Least Cost among plans 计划中成本最低的

在这里插入图片描述

How to compute Wasserstein Distance

在这里插入图片描述

WGAN

在这里插入图片描述

Sort of Regularization

高斯数据Gaussians
在这里插入图片描述

WGAN-Gradient Penalty 梯度惩罚

在这里插入图片描述

More stable

在这里插入图片描述
在这里插入图片描述

实战:GAN

import torch
from torch import nn, optim, autograd
import numpy as np
import visdom
import random

from matplotlib import pyplot as plt

h_dim = 400
batchsz = 512 #这里由于数据量计较少,可以设置大一些,这个值是根据显存来决定的
viz = visdom.Visdom()

class Generator(nn.Module):

    def __init__(self):
        super(Generator, self).__init__()

        self.net = nn.Sequential(
            #输入中的2是可以随机的,不一定是2,也可以是20
            #输出中的2是固定的,因为我们要查看结果,因此将其输出为2维。便于在平面上绘制出来结果。
            #z:[b, 2] => [b, 2]
            #一共有四层
            nn.Linear(2,h_dim),
            nn.ReLU(True),
            nn.Linear(h_dim,h_dim),
            nn.ReLU(True),
            nn.Linear(h_dim,2),
        )

    def forward(self,z):
        output = self.net(z)
        return output

class Discriminator(nn.Module):
    def __init__(self):
        super(Discriminator, self).__init__()

        self.net = nn.Sequential(
            nn.Linear(2,h_dim),
            nn.ReLU(True),
            nn.Linear(h_dim,h_dim),
            nn.ReLU(True),
            nn.Linear(h_dim,h_dim),
            nn.ReLU(True),
            nn.Linear(h_dim,1),
            nn.Sigmoid(),
            #输出为1的话,表示数据来自于真实分布的概率非常高,不是由Genator生成的。
            #输出如果为0的话,表示这个x可能是由生成器生成的。
        )
    def forward(self,x):
        output = self.net(x)
        return output.view(-1) #注意这里降维了,代表概率

def  data_generator():
    """
    8-gaussian mixture models
    :return:
    """
    #这里是根据已知的分布,来查看gan是否可以学习出来。
    scale = 2.
    centers = [
        (1,0),
        (-1,0),
        (0,1),
        (0,-1),
        (1. / np.sqrt(2),1. / np.sqrt(2)),
        (1. / np.sqrt(2),-1. / np.sqrt(2)),
        (-1. / np.sqrt(2), 1 / np.sqrt(2)),
        (-1. / np.sqrt(2), -1 / np.sqrt(2))
    ]
    #centers是0和1的分布,通过scale对centers进行缩放处理
    centers = [(scale * x , scale * y ) for x, y in centers]

    while True:
        dataset = []

        #batchsz是512
        for i in range(batchsz):
            point = np.random.randn(2) *0.02 #随机生成两个值
            center = random.choice(centers) #从上面center的8个点中任意选一个出来
            #N(0,1) + center_x1/x2
            point[0] += center[0]
            point[1] += center[1]
            #将这个点添加到dataset中
            dataset.append(point)

        #转为numpy
        dataset = np.array(dataset).astype(np.float32)
        dataset /= 1.414
        #死循环生成器:每完成一次循环,就跳出,并保存这一次循环的最终状态,下次循环会从这个最终状态开始循环下一次。
        yield dataset

#可视化函数
#用于显示sample点与我们理想分布的8个高斯点分布情况,样本点是否符合那八个高斯点的分布。
def generate_image(D, G, xr, epoch):
    """
    Generates and saves a plot of the true distribution, the generator, and the
    critic.
    """
    N_POINTS = 128
    RANGE = 3
    plt.clf()

    points = np.zeros((N_POINTS, N_POINTS, 2), dtype='float32')
    points[:, :, 0] = np.linspace(-RANGE, RANGE, N_POINTS)[:, None]
    points[:, :, 1] = np.linspace(-RANGE, RANGE, N_POINTS)[None, :]
    points = points.reshape((-1, 2))
    # (16384, 2)
    # print('p:', points.shape)

    # draw contour
    with torch.no_grad():
        points = torch.Tensor(points).cuda() # [16384, 2]
        disc_map = D(points).cpu().numpy() # [16384]
    x = y = np.linspace(-RANGE, RANGE, N_POINTS)
    cs = plt.contour(x, y, disc_map.reshape((len(x), len(y))).transpose())
    plt.clabel(cs, inline=1, fontsize=10)
    # plt.colorbar()


    # draw samples
    with torch.no_grad():
        z = torch.randn(batchsz, 2).cuda() # [b, 2]
        samples = G(z).cpu().numpy() # [b, 2]
    plt.scatter(xr[:, 0].cpu().numpy(), xr[:, 1].cpu().numpy(), c='orange', marker='.')
    plt.scatter(samples[:, 0], samples[:, 1], c='green', marker='+')

    viz.matplot(plt, win='contour', opts=dict(title='p(x):%d'%epoch))



def main():

    #先设置一下种子
    torch.manual_seed(23)
    np.random.seed(23)

    data_iter = data_generator()
    #通过next函数获得一次sample
    x = next(data_iter)
    print(x.shape) #其结果为(512,2)

    G = Generator().cuda()
    D = Discriminator().cuda()
    #可以查看一下网络结构
    # print(G)
    # print(D)

    #优化器
    optim_G = optim.Adam(G.parameters(),lr = 5e-4, betas = (0.5,0.9))
    optim_D = optim.Adam(D.parameters(),lr = 5e-4, betas = (0.5,0.9))

    #生成两个曲线
    #1、discrimination和loss_generator
    viz.line([[0,0]],[0],win='loss',opts=dict(title='loss',legend = ['D','G']))

    #编写GAN的核心部分
    for epoch in range(50000):
        #G和D彼此间交互着train
        #先train判别器,再train生成器
        #判别器可能一次train 1-5次

        #先train判别器5次,再train生成器

        #1、train Discriminator firstly
        #因为只优化Discriminator所以不需要计算generator的梯度
        #优化1-5步
        for _ in range(5):
            #有两个loss的来源,一个是真实值,一个是fake值
            #1.1、train on real data
            #真实数据:
            xr = next(data_iter) #这里类型是numpy需要转换
            xr = torch.from_numpy(xr).cuda()
            #[b,2] => [b,1]
            predr = D(xr)
            # max predr, min lossr
            #最大化predr,就是最小化loss的反方向
            #因此要改变其方向,需要加一个负号
            #因为我们使用的梯度下降,因此加一个符号,获得最大值。
            lossr = -predr.mean()

            #1.2、train on fake data
            # [b,2]
            z = torch.randn(batchsz ,2).cuda()
            #生成fake data
            #.detach()就是用来限制,是否计算梯度的,有detach存在,回退计算梯度就用因为有detach存在而断开,从而停止计算梯度。
            #因为我们只优化Discriminator,所以回退梯度到生成器前停止计算梯度。
            #所以generator的梯度是不需要计算的。
            xf = G(z).detach() #.detach()类似于tenseflow的tf.stop_gradient()
            #将fake data输入到判别器中
            predf = D(xf)
            #这里是需要最小值的
            lossf = predf.mean()

            #aggregate all
            loss_D = lossr + lossf

            #optimize
            optim_D.zero_grad()
            loss_D.backward()
            optim_D.step()

        #2、train Generator
        z = torch.randn(batchsz, 2).cuda()
        xf = G(z)
        # 这部分是在继承图的后面,没办法.detach(),只能加进来,也就是判别器的梯度先计算了,只要我们不更新判别器就可以了。
        # 这里我们只更新生成器的梯度,因为我们计算了判别器的梯度,因此我们必须要将优化器清零。
        predf = D(xf)
        #max predf.mean()
        loss_G = -predf.mean()

        #optimize
        optim_G.zero_grad()
        loss_G.backward()
        optim_G.step()

        if epoch % 100 ==0:
            viz.line([[loss_D.item(),loss_G.item()]],[epoch],win='loss',update='append')
            print('loss_D:',loss_D.item(),'; loss_G:',loss_G.item())

            generate_image(D,G,xr,epoch)


if __name__ == '__main__':
    main()

可以发现:
GAN的生成器效果很不好,使得判别器可以非常好的区分出真实数据和假数据,所以判别器的误差为0,GAN train的不稳定,生成器是恒定的,没有梯度信息,生成器长期得不到更新,因此判别器可以很好分别real data和fake data,但是生成器,由于JS divergence,不能很好的衡量两个没有重叠的distribution divergence,因此generator得不到更新,generator的loss一直处于恒定的loss,这个就是原始GAN出现的问题。
在这里插入图片描述
其中左侧小全的黄色点就是8个高斯分布模型,右侧绿色点就是sample点,这些sample点和我们想象的8个高斯分布情况完全不一样,现在这个GAN还没有收敛,效果很不好。
在这里插入图片描述

实战:WGAN 如何解决GAN train不稳定的问题

WGAN 如何让 GAN的training变得稳定。

WGAN-Gradient Penalty 梯度惩罚
在这里插入图片描述

import torch
from torch import nn, optim, autograd
import numpy as np
import visdom
import random

from matplotlib import pyplot as plt

h_dim = 400
batchsz = 512 #这里由于数据量计较少,可以设置大一些,这个值是根据显存来决定的
viz = visdom.Visdom()

class Generator(nn.Module):

    def __init__(self):
        super(Generator, self).__init__()

        self.net = nn.Sequential(
            #输入中的2是可以随机的,不一定是2,也可以是20
            #输出中的2是固定的,因为我们要查看结果,因此将其输出为2维。便于在平面上绘制出来结果。
            #z:[b, 2] => [b, 2]
            #一共有四层
            nn.Linear(2,h_dim),
            nn.ReLU(True),
            nn.Linear(h_dim,h_dim),
            nn.ReLU(True),
            nn.Linear(h_dim,2),
        )

    def forward(self,z):
        output = self.net(z)
        return output

class Discriminator(nn.Module):
    def __init__(self):
        super(Discriminator, self).__init__()

        self.net = nn.Sequential(
            nn.Linear(2,h_dim),
            nn.ReLU(True),
            nn.Linear(h_dim,h_dim),
            nn.ReLU(True),
            nn.Linear(h_dim,h_dim),
            nn.ReLU(True),
            nn.Linear(h_dim,1),
            nn.Sigmoid(),
            #输出为1的话,表示数据来自于真实分布的概率非常高,不是由Genator生成的。
            #输出如果为0的话,表示这个x可能是由生成器生成的。
        )
    def forward(self,x):
        output = self.net(x)
        return output.view(-1) #注意这里降维了,代表概率

def  data_generator():
    """
    8-gaussian mixture models
    :return:
    """
    #这里是根据已知的分布,来查看gan是否可以学习出来。
    scale = 2.
    centers = [
        (1,0),
        (-1,0),
        (0,1),
        (0,-1),
        (1. / np.sqrt(2),1. / np.sqrt(2)),
        (1. / np.sqrt(2),-1. / np.sqrt(2)),
        (-1. / np.sqrt(2), 1 / np.sqrt(2)),
        (-1. / np.sqrt(2), -1 / np.sqrt(2))
    ]
    #centers是0和1的分布,通过scale对centers进行缩放处理
    centers = [(scale * x , scale * y ) for x, y in centers]

    while True:
        dataset = []

        #batchsz是512
        for i in range(batchsz):
            point = np.random.randn(2) *0.02 #随机生成两个值
            center = random.choice(centers) #从上面center的8个点中任意选一个出来
            #N(0,1) + center_x1/x2
            point[0] += center[0]
            point[1] += center[1]
            #将这个点添加到dataset中
            dataset.append(point)

        #转为numpy
        dataset = np.array(dataset).astype(np.float32)
        dataset /= 1.414
        #死循环生成器:每完成一次循环,就跳出,并保存这一次循环的最终状态,下次循环会从这个最终状态开始循环下一次。
        yield dataset

#可视化函数
def generate_image(D, G, xr, epoch):
    """
    Generates and saves a plot of the true distribution, the generator, and the
    critic.
    """
    N_POINTS = 128
    RANGE = 3
    plt.clf()

    points = np.zeros((N_POINTS, N_POINTS, 2), dtype='float32')
    points[:, :, 0] = np.linspace(-RANGE, RANGE, N_POINTS)[:, None]
    points[:, :, 1] = np.linspace(-RANGE, RANGE, N_POINTS)[None, :]
    points = points.reshape((-1, 2))
    # (16384, 2)
    # print('p:', points.shape)

    # draw contour
    with torch.no_grad():
        points = torch.Tensor(points).cuda() # [16384, 2]
        disc_map = D(points).cpu().numpy() # [16384]
    x = y = np.linspace(-RANGE, RANGE, N_POINTS)
    cs = plt.contour(x, y, disc_map.reshape((len(x), len(y))).transpose())
    plt.clabel(cs, inline=1, fontsize=10)
    # plt.colorbar()


    # draw samples
    with torch.no_grad():
        z = torch.randn(batchsz, 2).cuda() # [b, 2]
        samples = G(z).cpu().numpy() # [b, 2]
    plt.scatter(xr[:, 0].cpu().numpy(), xr[:, 1].cpu().numpy(), c='orange', marker='.')
    plt.scatter(samples[:, 0], samples[:, 1], c='green', marker='+')

    viz.matplot(plt, win='contour', opts=dict(title='p(x):%d'%epoch))


#gradient_penalty梯度惩罚
def gradient_penalty(D,xr,xf):
    """
    这个惩罚项可以理解为regularization模式:
    就是将discrimination约束成one liability function
    :param D:
    :param xr: [b,2]
    :param xf: [b,2]
    :return:
    """

    #随机sample一个均值分布,维度是[b,1]
    t = torch.rand(batchsz,1).cuda()
    #[b,1] => [b,2]
    #这里需要注意的是,为什么上面不直接生成一个2,而是用下面这种方法。
    #这是因为要保持同样的sample,其中t是相同的,所以先通过uniform的分布,sample出b个,之后再expand
    #对于一个同样的sample,其权值是相同的。
    t = t.expand_as(xr)
    # 线性差值,真实与fake data的线性差值
    mid = t * xr + (1-t) * xf
    #需要有导数信息set it requires gradient
    mid.requires_grad_()

    pred = D(mid)
    grads = autograd.grad(outputs=pred,
                          inputs=mid,
                          grad_outputs=torch.ones_like(pred),
                          create_graph=True, #这个参数是用来二阶求导,如果需要二阶求导就需要设置这个参数。
                          retain_graph=True, #如果这个图还需要再backward一次,就需要保留这个梯度信息,不然后续的backward就会报错。
                          )[0]

    #平方和:torch.pow(,2)
    #.norm(2,dim=1) 表示求2范数:向量元素绝对值的平方和再开方
    #这里我们要2范数越接近1越好
    gp = torch.pow(grads.norm(2,dim=1) - 1, 2).mean()
    return gp

def main():

    #先设置一下种子
    torch.manual_seed(23)
    np.random.seed(23)

    data_iter = data_generator()
    #通过next函数获得一次sample
    x = next(data_iter)
    print(x.shape) #其结果为(512,2)

    G = Generator().cuda()
    D = Discriminator().cuda()
    #可以查看一下网络结构
    # print(G)
    # print(D)

    #优化器
    optim_G = optim.Adam(G.parameters(),lr = 5e-4, betas = (0.5,0.9))
    optim_D = optim.Adam(D.parameters(),lr = 5e-4, betas = (0.5,0.9))

    #生成两个曲线
    #1、discrimination和loss_generator
    viz.line([[0,0]],[0],win='loss',opts=dict(title='loss',legend = ['D','G']))

    #编写GAN的核心部分
    for epoch in range(50000):
        #G和D彼此间交互着train
        #先train判别器,再train生成器
        #判别器可能一次train 1-5次

        #先train判别器5次,再train生成器

        #1、train Discriminator firstly
        #因为只优化Discriminator所以不需要计算generator的梯度
        #优化1-5步
        for _ in range(5):
            #有两个loss的来源,一个是真实值,一个是fake值
            #1.1、train on real data
            #真实数据:
            xr = next(data_iter) #这里类型是numpy需要转换
            xr = torch.from_numpy(xr).cuda()
            #[b,2] => [b,1]
            predr = D(xr)
            # max predr, min lossr
            #最大化predr,就是最小化loss的反方向
            #因此要改变其方向,需要加一个负号
            #因为我们使用的梯度下降,因此加一个符号,获得最大值。
            lossr = -predr.mean()

            #1.2、train on fake data
            # [b,2]
            z = torch.randn(batchsz ,2).cuda()
            #生成fake data
            #.detach()就是用来限制,是否计算梯度的,有detach存在,回退计算梯度就用因为有detach存在而断开,从而停止计算梯度。
            #因为我们只优化Discriminator,所以回退梯度到生成器前停止计算梯度。
            #所以generator的梯度是不需要计算的。
            xf = G(z).detach() #.detach()类似于tenseflow的tf.stop_gradient()
            #将fake data输入到判别器中
            predf = D(xf)
            #这里是需要最小值的
            lossf = predf.mean()

            #1.3、gradient penalty惩罚项
            #这里我们不需要对生成器求导,xf是生成器生成的,因此需要.detach()一下,让其不求导
            gp = gradient_penalty(D,xr,xf.detach())

            #aggregate all
            loss_D = lossr + lossf + 0.2 * gp

            #optimize
            optim_D.zero_grad()
            loss_D.backward()
            optim_D.step()

        #2、train Generator
        z = torch.randn(batchsz, 2).cuda()
        xf = G(z)
        # 这部分是在继承图的后面,没办法.detach(),只能加进来,也就是判别器的梯度先计算了,只要我们不更新判别器就可以了。
        # 这里我们只更新生成器的梯度,因为我们计算了判别器的梯度,因此我们必须要将优化器清零。
        predf = D(xf)
        #max predf.mean()
        loss_G = -predf.mean()

        #optimize
        optim_G.zero_grad()
        loss_G.backward()
        optim_G.step()

        if epoch % 100 ==0:
            viz.line([[loss_D.item(),loss_G.item()]],[epoch],win='loss',update='append')
            print('loss_D:',loss_D.item(),'; loss_G:',loss_G.item())

            generate_image(D,G,xr,epoch)


if __name__ == '__main__':
    main()

八个黄色的点是高斯模型点,sample的话在八个高斯点附件的概率是最大的,绿色点是生成的数据点,最好情况是sample出来的绿色点越接近八个高斯点越好。
在这里插入图片描述

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

PyTorch-12 GAN、WGAN 的相关文章

随机推荐

  • MyBatis介绍及教程

    MyBatis简介 MyBatis 是支持定制化 SQL 存储过程以及高级映射的优秀的持久层框架 MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集 MyBatis 可以对配置和原生Map使用简单的 XML 或注解
  • 华为OD机试 - 叠积木(Java)

    题目描述 有一堆长方体积木 它们的宽度和高度都相同 但长度不一 小橙想把这堆积木叠成一面墙 墙的每层可以放一个积木 也可以将两个积木拼接起来 要求每层的长度相同 若必须用完这些积木 叠成的墙最多为多少层 输入描述 输入为一行 为各个积木的长
  • python安装出错

    按照python 程序时候报错 没有更新python 版本 按照上面查看的 pyhon3 m pip install upgrade pip 将命令行路径移到安装python目录下 输入 python exe m pip install u
  • 时间戳获取

  • 在Nuxt应用程序中关闭webpack-hot-middleware客户端覆盖

    有时候 因为代码的语法错误 nuxt界面会弹出 但是 有时候因为缓等原因 即使修复了语法错误 这个提示错误的界面仍然存在 那么 出现这种情况 怎么禁止出这个界面弹出 该如何关闭它呢 在nuxt config js当中配置 overlay f
  • Linux-MYSQL

    1 C语言连接mysql 读 写 2 视图 索引 事务 端口 3306 一 基本操作 1 源码安装 2 命令安装 sudo su gt apt install mysql server 查看进程是否再运行 service mysql sta
  • 20天学会Java-基础阶段笔记

    视频地址 https www bilibili com video BV1Cv411372m 此笔记是 P1 P85 1 开始 1 1 注释 理解 注释是对代码的解释和说明文字 可以提高程序的可读性 因此在程序中添加必要的注释文字十分重要
  • 【千律】C++基础:通过递归函数计算N的阶乘

    include
  • 修改照片尺寸25mm*35mm

    打开方式 画图 gt 调整图片大小 选择像素 gt 修改为295 413即可
  • OpenCloudOS 8 安装rabbitMQ 和Docker

    文章目录 安装环境 Docker CE 安装rabbitMq 安装步骤 1 引入签名 2 为 RabbitMQ 和 Modern Erlang 添加 Yum 仓库 3 更新yum元数据 缓存rabbitmq相关的仓库数据 4 yum安装依赖
  • vue + moment 实现倒计时

    示例 代码 span countDown endDate span 引入日期插件 import moment from moment export default data return now moment endDate 2019 05
  • Windows和iPad传输

    一 电脑操作 1 新建文件夹 2 设置文件夹的属性 选着共享 3 设置高级共享 权限选择完全控制 4 选择共享 选择Everyone 5 在windows搜索栏中输入cmd 打开命令提示符窗口 6 输入ipconfig回车 7 记住你的ip
  • python爬取豆瓣电影json数据

    由于豆瓣里的电影都有专属的id 获取到id后可以进一步爬取其他页面的内容 首先来到主界面 https movie douban com 观察网页 点击 选电影 进入需要爬取的界面 打开Chrome开发模式 并下拉网页观察新生成的文件 可以观
  • Cause: java.sql.SQLIntegrityConstraintViolationException: Column ‘xxx‘ cannot be null

    1 报错信息 2 定位错误的范围 SQL insert into business businessId password salt businessName businessAddress businessExplain starPric
  • 【基于Cocos Creator实现的赛车游戏】9.实现汽车节点的控制逻辑

    转载知识星球 深度连接铁杆粉丝 运营高品质社群 知识变现的工具 项目地址 赛车小游戏 基于Cocos Creator 3 5版本实现 课程的源码 基于Cocos Creator 3 5版本实现 在上一节的课程中 您已经实现了通过触控给刚体施
  • RCP系列-第一章 环境安装

    RCP系列文章 第一章 Matlab安装 Matlab安装 RCP系列文章 前言 一 Matlab 获取 二 安装 1 解压 2 打开解压后的文件夹中的 R2018b win64 文件夹 3 鼠标右击 setup 选择 以管理员身份运行 4
  • oswatch的安装和使用

    author skate time 2011 08 06 oswatch的安装和使用 1 下载和安装 oswatch的安装与使用也比较简单 和nmon一样 都是下载后直接解压就可以使用的 oswatch是通过调用系统的命令完成信息的收集 命
  • 【Transformer系列(3)】 《Attention Is All You Need》论文超详细解读(翻译+精读)

    前言 哒哒 时隔好久终于继续出论文带读了 这次回归当然要出一手王炸呀 没错 今天我们要一起学习的就是传说中的Transformer 在2021年Transformer一经论文 Attention is All You Need 提出 就如龙
  • java数组学习

    2021 2 2 数组 一维数组的使用 1 一维数组的声明和初始化 2 如何调用数组的指定位置的元素 3 如何获取数组的长度 4 如何遍历数组 5 数组元素的默认初始化值 6 数组的内存解析 package day01 import jav
  • PyTorch-12 GAN、WGAN

    PyTorch 12 生成对抗网络 GAN WGAN 参考 https zhuanlan zhihu com p 34287744 GAN模型的目标函数如下 GAN模型优化训练 在训练过程中 生成网络的目标就是尽量生成真实的图片去欺骗判别网