利用深度学习模型解决数据稀疏问题

2023-04-28  本文已影响0人  小潤澤

前言

阅读文献《PHIAF: prediction of phage-host interactions with GAN-based data augmentation and sequence-based feature fusion》
GitHub 地址:https://github.com/BioMedicalBigDataMiningLab/PHIAF/blob/master/code/generate_data.py

这个项目由于正样本数据稀疏,数据量不够支撑进行深度学习的量,因此现在有限的正样本中学习一个分别,然后在对这个分布进行采样,得到一个大的负样本数据集,然后再进行深度学习

GAN 原理

作者本文采用了GAN模型(生成对抗神经网络)

GAN的基本原理其实非常简单,这里以生成数据为例进行说明。假设我们有两个网络,G(Generator)和D(Discriminator)。正如它的名字所暗示的那样,它们的功能分别是:

  1. G是一个生成数据的网络,它接收一个随机的噪声z,通过这个噪声生成数据,记做G(z)。
  2. D是一个判别网络,判别数据是不是“真实的”。它的输入参数是x,x代表一张数据,输出D(x)代表x为真实数据的概率,如果为1,就代表100%是真实的数据,而输出为0,就代表不可能是真实的数据。
    在训练过程中,生成网络G的目标就是尽量生成真实的数据去欺骗判别网络D。而D的目标就是尽量把G生成的数据和真实的数据分别开来。这样,G和D构成了一个动态的“博弈过程”。在最理想的状态下,G可以生成足以“以假乱真”的数据G(z)
    传送门

GAN 代码实例

import numpy as np
import torch
import torch.nn as nn
import torch.optim as optim

torch.manual_seed(1)
np.random.seed(1)


class Generator(nn.Module):
    def __init__(self):
        super(Generator, self).__init__()
        self.model = nn.Sequential(
            nn.Linear(16, 128),
            nn.LeakyReLU(),
            nn.Dropout(p=0.3),
            nn.Linear(128, 256),
            nn.LeakyReLU(),
            nn.Dropout(p=0.3),
            nn.Linear(256, 512)
        )

    def forward(self, inputs):
        return self.model(inputs)


class Discriminator(nn.Module):
    def __init__(self):
        super(Discriminator, self).__init__()
        self.model = nn.Sequential(
            nn.Linear(512, 256),
            nn.Tanh(),
            nn.Linear(256, 128),
            nn.Tanh(),
            nn.Linear(128, 1),
            nn.Sigmoid()
        )

    def forward(self, inputs):
        return self.model(inputs)


def train():
    G_mean = []
    G_std = []  # 用于记录生成器生成的数据的均值和方差
    data_mean = 3
    data_std = 1  # 目标分布的均值和方差
    batch_size = 64
    g_input_size = 16
    g_output_size = 512

    epochs = 1001
    d_epoch = 10  # 每个epoch判别器的训练轮数

    # 初始化网络
    D = Discriminator()
    G = Generator()

    # 初始化优化器和损失函数
    d_learning_rate = 0.01
    g_learning_rate = 0.001
    ## 定义损失函数 BCELoss()
    loss_func = nn.BCELoss()  # - [p * log(q) + (1-p) * log(1-q)]
    optimiser_D = optim.Adam(D.parameters(), lr=d_learning_rate)
    optimiser_G = optim.Adam(G.parameters(), lr=g_learning_rate)

    for epoch in range(epochs):
        G.train()
        # 训练判别器d_steps次
        for _ in range(d_epoch):
            # 真实数据 real_data 输入D(),得到 d_real
            real_data = torch.tensor(np.random.normal(data_mean, data_std, (batch_size, g_output_size)),
                                     dtype=torch.float)

            # 利用判别器学习真实数据,D() 函数将计算出一列向量 d_real,优化的目标是使得这列向量 d_real->1
            d_real = D(real_data)
            # 随机生成一列伪数据
            g_input = torch.rand(batch_size, g_input_size)
            # 利用生成器 G() 生成伪数据
            fake_data = G(g_input).detach()  # detach:只生成结果向量,不参与反向传播
            # 利用判别器学习伪数据,D() 函数将计算出一列向量 d_fake,优化的目标是使得这列向量 d_fake->0
            d_fake = D(fake_data)

            # 计算损失值,判别器学习使得d_real->1,d_fake->0,这里判别器的激活函数是 Sigmoid()
            # 因此真实数据 real_data 的标签为 1; 伪数据 fake_data 的标签为 0

            # 计算判别器 D() 所得出真实数据的结果向量 d_real 与标签 1 的损失
            loss_d_real = loss_func(d_real, torch.ones([batch_size, 1]))
            # 计算判别器 D() 所得出伪数据的结果向量 d_fake 与标签 0 的损失
            loss_d_fake = loss_func(d_fake, torch.zeros([batch_size, 1]))
            # 总损失为 loss_d_real 和 loss_d_fake 之和
            d_loss = loss_d_real + loss_d_fake

            # 反向传播,优化
            optimiser_D.zero_grad()
            d_loss.backward()
            ## 判别器的优化参数迭代
            optimiser_D.step()

        # 训练生成器
        # 随机生成同维度的向量 g_input,利用生成器 G() 生成伪数据 fake_data
        # 将伪数据 fake_data 放入判别器 D() 中判断,生成结果向量 d_g_fake
        g_input = torch.rand(batch_size, g_input_size)
        fake_data = G(g_input)
        d_g_fake = D(fake_data)

        # GAN 的目的是使得生成器 G() 生成的数据接近真实数据
        # 计算损失值,使得 d_g_fake->1,使得生成器 G() 生成的数据能让判别器 D() 判断成 “1”
        loss_G = loss_func(d_g_fake, torch.ones([batch_size, 1]))

        # 反向传播,优化
        optimiser_G.zero_grad()
        loss_G.backward()
        optimiser_G.step()
        # 记录生成器输出的均值和方差
        G_mean.append(fake_data.mean().item())
        G_std.append(fake_data.std().item())

        if epoch % 10 == 0:
            print("Epoch: {}, 生成数据的均值: {}, 生成数据的标准差: {}".format(epoch, G_mean[-1], G_std[-1]))
            print('-' * 10)
            G.eval()

if __name__ == '__main__':
    train()

原理:GAN 的基本概念是产生生成器 Generator 和判别器 Discriminator,Generator 负责生成伪数据,而 Discriminator 负责判断 Generator 产生的伪数据是否能够以假乱真。两者不断地更新参数,相互竞争
步骤:

  1. 训练Discriminator:首先 Discriminator 需要基于真实数据计算出真实数据的结果向量 d_real ,然后基于随机生成的数据(伪数据)计算出伪数据的结果向量 d_fake,然后基于损失函数,使得 d_fake 更接近于负类 0 ,d_real 更接近于正类 1
  2. 训练Generator :随机生成同维度的向量后,经过 Generator 产生结果向量 fake_data ,然后利用训练好的 Discriminator 判断 fake_data 是否为 "真实数据":即基于 fake_data 利用 Discriminator 计算出结果向量 d_g_fake ,然后基于损失函数,使得 d_g_fake 更接近于正类 1,这样判别器 Discriminator 认为 Generator 产生的数据都是"真实数据"了,此时 Generator 产生的伪数据可以达到以假乱真的效果,从而可以 Generator 产生的伪数据当作真实数据

phiaf 代码

1. 预处理DNA序列

对于预处理DNA序列的脚本,compute_dna_features.py

import numpy as np
import os
import warnings
warnings.filterwarnings("ignore")
import pandas as pd
from sklearn import preprocessing


for mm in ['phage','host']:
    for method in ['Kmer','RCKmer','NAC','DNC','TNC','CKSNAP','PseEIIP']:
        print(mm,method)
        os.system('python /home/software/PHIAF/iLearn/iLearn-nucleotide-basic.py --file /home/rzli/phiaf/all%s_dna_seq.fasta --method %s --format csv --out /home/rzli/phiaf/all%s_seq_%s.csv'%(mm,method,method,mm))


phage1=np.loadtxt('/home/phiaf/allKmer_seq_phage.csv',delimiter=',')[:,1:]
host1=np.loadtxt('/home/phiaf/allKmer_seq_host.csv',delimiter=',')[:,1:]

for method in ['RCKmer','NAC','DNC','TNC','CKSNAP','PseEIIP']:
    phage2=np.loadtxt('/home/phiaf/all'+method+'_seq_phage.csv',delimiter=',')[:,1:]
    host2=np.loadtxt('/home/phiaf/all'+method+'_seq_host.csv',delimiter=',')[:,1:]
    
    # 合并 Kmer,RCKmer,NAC,DNC,TNC,CKSNAP,PseEIIP
    phage1=np.hstack((phage1,phage2))
    host1=np.hstack((host1,host2))


## 获得 phage 和 host 的分类信息
inters=pd.read_csv('/home/phiaf/data_pos_neg.txt',header=None,sep='\t')
phages=[]
hosts=[]
for i in inters.index:
    phages.append(inters.loc[i,0].split(',')[0])
    hosts.append(inters.loc[i,0].split(',')[1])
# 得到 phages 和 host 的 sample 号
phages=list(set(phages))
hosts=list(set(hosts))


min_max_scaler1 = preprocessing.MinMaxScaler()
# 对 phage1 向量进行归一化
phage_features_norm = min_max_scaler1.fit_transform(phage1)
min_max_scaler2 = preprocessing.MinMaxScaler()
# 对 host1 向量进行归一化
host_features_norm = min_max_scaler2.fit_transform(host1)

# 
for pp in range(len(phages))::
    np.savetxt('/home/phiaf/'+phages[pp]+'.txt',phage_features_norm[pp,:])
for hh in range(len(hosts))::
    np.savetxt('/home/phiaf/'+hosts[hh]+'.txt',host_features_norm[hh,:])

首先 data_pos_neg.txt 长这样,第一列是 phage,第二列是 host,第三列的 0 和 1代表 phage与host是否能互作 1 代表能;0 代表不能


我们可以了解到,作者将所有的 host contigs 和 phage contigs 分别合并为 allhost_dna_seq.fasta 和 allphage_dna_seq.fasta

  1. allhost_dna_seq.fasta:三个不同 host contigs 的 fa 文件合并到一起


  2. allhost_dna_seq.fasta:三个不同 phage contigs 的 fa 文件合并到一起


  3. Kmers 计算出来的结果为: host

    每一个 host(phage)的contigs 将会计算出一列向量

  4. NAC 计算出来的结果为: host

    每一个 host(phage)的contigs 将会计算出一列向量

  5. RCKmer 计算出来的结果为: host

    每一个 host(phage)的contigs 将会计算出一列向量

  6. DNC 计算出来的结果为: host

    每一个 host(phage)的contigs 将会计算出一列向量

  7. TNC 计算出来的结果为: host

    每一个 host(phage)的contigs 将会计算出一列向量

  8. CKSNAP 计算出来的结果为: host

    每一个 host(phage)的contigs 将会计算出一列向量

  9. PseEIIP 计算出来的结果为: host
    每一个 host(phage)的contigs 将会计算出一列向量
    注:phage和host结果的格式相似

2. 预处理蛋白质序列

import os
import pandas as pd
import numpy as np
import warnings

warnings.filterwarnings("ignore")
from collections import Counter
from Bio.SeqUtils.ProtParam import ProteinAnalysis
from Bio import SeqIO
from sklearn import preprocessing


def file_name(file_dir, gb_fas):
    for root, dirs, files in os.walk(file_dir):
        LL1 = []
        for ff in files:
            if os.path.splitext(ff)[1] == gb_fas:
                LL1.append(os.path.join(ff))
        return LL1


# Encode the AAC feature with the protein sequence
def AAC_feature(fastas):
    AA = 'ACDEFGHIKLMNPQRSTVWY*'
    encodings = []
    header = ['#']
    for i in AA:
        header.append(i)
    encodings.append(header)
    sequence = fastas
    count = Counter(sequence)
    for key in count:
        count[key] = float(count[key]) / len(sequence)
    code = []
    for aa in AA:
        code.append(count[aa])
    encodings.append(code)
    return code

## 计算蛋白质序列理化性质的函数
# Extract the physical-chemical properties from the protein sequence
def physical_chemical_feature(sequence):
    seq_new = sequence.replace('X', '').replace('U', '').replace('B', '').replace('Z', '').replace('J', '')
    CE = 'CHONS'
    ## 理化性质参数
    Chemi_stats = {'A': {'C': 3, 'H': 7, 'O': 2, 'N': 1, 'S': 0},
                   'C': {'C': 3, 'H': 7, 'O': 2, 'N': 1, 'S': 1},
                   'D': {'C': 4, 'H': 7, 'O': 4, 'N': 1, 'S': 0},
                   'E': {'C': 5, 'H': 9, 'O': 4, 'N': 1, 'S': 0},
                   'F': {'C': 9, 'H': 11, 'O': 2, 'N': 1, 'S': 0},
                   'G': {'C': 2, 'H': 5, 'O': 2, 'N': 1, 'S': 0},
                   'H': {'C': 6, 'H': 9, 'O': 2, 'N': 3, 'S': 0},
                   'I': {'C': 6, 'H': 13, 'O': 2, 'N': 1, 'S': 0},
                   'K': {'C': 6, 'H': 14, 'O': 2, 'N': 2, 'S': 0},
                   'L': {'C': 6, 'H': 13, 'O': 2, 'N': 1, 'S': 0},
                   'M': {'C': 5, 'H': 11, 'O': 2, 'N': 1, 'S': 1},
                   'N': {'C': 4, 'H': 8, 'O': 3, 'N': 2, 'S': 0},
                   'P': {'C': 5, 'H': 9, 'O': 2, 'N': 1, 'S': 0},
                   'Q': {'C': 5, 'H': 10, 'O': 3, 'N': 2, 'S': 0},
                   'R': {'C': 6, 'H': 14, 'O': 2, 'N': 4, 'S': 0},
                   'S': {'C': 3, 'H': 7, 'O': 3, 'N': 1, 'S': 0},
                   'T': {'C': 4, 'H': 9, 'O': 3, 'N': 1, 'S': 0},
                   'V': {'C': 5, 'H': 11, 'O': 2, 'N': 1, 'S': 0},
                   'W': {'C': 11, 'H': 12, 'O': 2, 'N': 2, 'S': 0},
                   'Y': {'C': 9, 'H': 11, 'O': 3, 'N': 1, 'S': 0}
                   }

    count = Counter(seq_new)
    code = []

    for c in CE:
        abundance_c = 0
        for key in count:
            num_c = Chemi_stats[key][c]
            abundance_c += num_c * count[key]

        code.append(abundance_c)
    return (code)


## 计算蛋白质分子量的函数
# calculate the protein molecular for the protein sequnce.
def molecular_weight(seq):
    # 删除蛋白质序列中的 'X' , 'U' , 'B' , 'Z' , 'J'
    seq_new = seq.replace('X', '').replace('U', '').replace('B', '').replace('Z', '').replace('J', '')
    analysed_seq = ProteinAnalysis(seq_new)
    analysed_seq.monoisotopic = True
    mw = analysed_seq.molecular_weight()
    return ([mw])


if __name__ == '__main__':
    inters = pd.read_csv('/home/phiaf/data_pos_neg.txt', header=None, sep='\t')
    phages = []
    hosts = []
    for i in inters.index:
        phages.append(inters.loc[i,0].split(',')[0])
        hosts.append(inters.loc[i,0].split(',')[1])
    phages = list(set(phages))
    hosts = list(set(hosts))

    ####gb file is download from NCBI
    phage_features = []
    for pp in phages:
        print(pp)
        a = []
        filepath = '/home/phiaf/phagegb/' + pp + '.gb'
        for record1 in SeqIO.parse(filepath, "genbank"):
            if (record1.features):
                myseq1 = record1.seq
                for feature1 in record1.features:
                    ## 提取 phage gbk 文件的 CDS translation 后的序列(蛋白质序列)
                    if feature1.type == "CDS" and 'translation' in feature1.qualifiers:
                        seq1 = feature1.qualifiers['translation'][0]
                        ## 计算蛋白质序列的理化性质, 分子量和 AAC 特征, 每条蛋白质序列都计算一次
                        a.append(physical_chemical_feature(seq1) + molecular_weight(seq1) + AAC_feature(seq1))
        xx = np.array(a)
        phage_features.append(xx.mean(axis=0).tolist() + xx.max(axis=0).tolist() + xx.min(axis=0).tolist() +
                              xx.std(axis=0).tolist() + xx.var(axis=0).tolist() + np.median(xx, axis=0).tolist())

        print(phage_features)
    host_features = []
    for hh in hosts:
        print(hh)
        a = []
        filepath = '/home/phiaf/hostgb/' + hh + '.gb'
        for record1 in SeqIO.parse(filepath, "genbank"):
            if (record1.features):
                myseq1 = record1.seq
                for feature1 in record1.features:
                    ## 提取 phage gbk 文件的 CDS translation 后的序列(蛋白质序列)
                    if feature1.type == "CDS" and 'translation' in feature1.qualifiers:
                        seq1 = feature1.qualifiers['translation'][0]
                        ## 计算蛋白质序列的理化性质, 分子量和 AAC 特征, 每条蛋白质序列都计算一次
                        a.append(physical_chemical_feature(seq1) + molecular_weight(seq1) + AAC_feature(seq1))
        xx = np.array(a)
        host_features.append(xx.mean(axis=0).tolist() + xx.max(axis=0).tolist() + xx.min(axis=0).tolist() +
                             xx.std(axis=0).tolist() + xx.var(axis=0).tolist() + np.median(xx, axis=0).tolist())
        print(host_features)


    ###save and normalize features
    min_max_scaler1 = preprocessing.MinMaxScaler()
    ## 向量归一化
    phage_features_norm = min_max_scaler1.fit_transform(phage_features)
    min_max_scaler2 = preprocessing.MinMaxScaler()
    ## 向量归一化
    host_features_norm = min_max_scaler2.fit_transform(host_features)
    for pp in range(3):
        np.savetxt('/home/phiaf/phage_protein_' + phages[pp] + '.txt', phage_features_norm[pp, :])
    for hh in range(3):
        np.savetxt('/home/phiaf/host_protein_' + hosts[hh] + '.txt', host_features_norm[hh, :])
每一个 gbk 文件生成:

形如这样的一列向量

3. 预处理的结果

对于 DNA 预处理后的结果(这里用3个contig为例子)



每一个 contig 将会生成一列向量:


对于 protein 预处理后的结果(这里用3个contig为例子)



每一个 contig 中所有 CDS 的蛋白质序列合起来将会生成一列向量:


4. 产生pseudo数据

代码:
step 1:定义初始函数以及读取文件

import os, sys
sys.path.append(os.getcwd())
import random
random.seed(1)
import numpy as np
import pandas as pd
import torch
import torch.autograd as autograd
import torch.nn as nn
import torch.optim as optim
torch.manual_seed(1)
from sklearn.model_selection import LeaveOneOut
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score
import warnings
warnings.filterwarnings("ignore")


def obtainfeatures(data, file_path1, strs):
    host_features = []
    for i in data:
        host_features.append(np.loadtxt(file_path1 + i + strs).tolist())
    return np.array(host_features)


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

        main = nn.Sequential(
            nn.Linear(shape1, 128),
            nn.ReLU(True),
            nn.Linear(128, 256),
            nn.ReLU(True),
            nn.Linear(256, 512),
            nn.ReLU(True),
            nn.Linear(512, 1024),
            nn.Tanh(),
            nn.Linear(1024, shape1),
        )
        # 执行 main 函数
        self.main = main

    def forward(self, noise):
        output = self.main(noise)
        return output



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

        self.fc1 = nn.Linear(shape1, 512)
        self.relu = nn.LeakyReLU(0.2)
        self.fc2 = nn.Linear(512, 256)
        self.relu = nn.LeakyReLU(0.2)
        self.fc3 = nn.Linear(256, 128)
        self.relu = nn.LeakyReLU(0.2)
        self.fc4 = nn.Linear(128, 1)

    def forward(self, inputs):
        out = self.fc1(inputs)
        out = self.relu(out)
        out = self.fc2(out)
        out = self.relu(out)
        out = self.fc3(out)
        out = self.relu(out)
        out = self.fc4(out)
        ## .view(-1)平铺成一维向量
        return out.view(-1)

# 定义生成模型 netG 和判别模型 netD 每一层的初始化权重参数
def weights_init(m):
    classname = m.__class__.__name__
    if classname.find('Linear') != -1:
        m.weight.data.normal_(0.0, 0.02)
        m.bias.data.fill_(0)
    elif classname.find('BatchNorm') != -1:
        m.weight.data.normal_(1.0, 0.02)
        m.bias.data.fill_(0)


# 读取训练数据的函数
def inf_train_gen(datas):
    with open('/home/rzli/phiaf/result/' + datas + '.txt') as f:
        MatrixFeaturesPositive = [list(x.split(" ")) for x in f]
    FeaturesPositive = [line[:] for line in MatrixFeaturesPositive[:]]
    dataset2 = np.array(FeaturesPositive, dtype='float32')
    return dataset2

## 定义惩罚项函数
def calc_gradient_penalty(netD, real_data, fake_data):
    alpha = torch.rand(BATCH_SIZE, 1)
    alpha = alpha.expand(real_data.size())
    alpha = alpha.cuda() if use_cuda else alpha
    interpolates = alpha * real_data + ((1 - alpha) * fake_data)
    if use_cuda:
        interpolates = interpolates.cuda()
    interpolates = autograd.Variable(interpolates, requires_grad=True)
    disc_interpolates = netD(interpolates)
    gradients = autograd.grad(outputs=disc_interpolates, inputs=interpolates,
                              grad_outputs=torch.ones(disc_interpolates.size()).cuda() if use_cuda else torch.ones(
                                  disc_interpolates.size()), create_graph=True, retain_graph=True, only_inputs=True)[0]
    gradient_penalty = ((gradients.norm(2, dim=1) - 1) ** 2).mean() * LAMBDA
    return gradient_penalty


# 读取第3步的数据列表 data_pos_neg.txt
data = pd.read_csv('/home/phiaf/data_pos_neg.txt', header=None, sep=',')
# 将 phage 能与 host 互作的互作对取出,即 data_pos_neg.txt 第三列数值为 1 
data = data[data[2] == 1].values.tolist()

# 分别获得 phage 能与 host 互作的互作对中,phage 的 contig 编号和 host 的 contig 编号
## 获得 phage 的 contig 编号
phage = [i[0] for i in data]
## 获得 host 的 contig 编号
host = [i[1] for i in data]

# 读取第3步所计算出来的 dna 和 protein 特征(每个 phage 和 host 对应的 contig 均含有 dna 和 protein 的一列特征向量)
phage_feature_pro = obtainfeatures(phage, '/home/phiaf/phage_protein_norm_features/protein_', '.txt')
phage_feature_dna = obtainfeatures(phage, '/home/phiaf/phage_dna_norm_features/dna_', '.txt')
host_feature_pro = obtainfeatures(host, '/home/phiaf/host_protein_norm_features/protein_', '.txt')
host_feature_dna = obtainfeatures(host, '/home/phiaf/host_dna_norm_features/dna_', '.txt')

# 将 phage 的 dna 和 protein 的特征向量进行合并
phage_all = np.concatenate((phage_feature_dna, phage_feature_pro), axis=1)
# 将 host 的 dna 和 protein 的特征向量进行合并
host_all = np.concatenate((host_feature_dna, host_feature_pro), axis=1)

###save features of real positive samples
# 将合并后的 phage 和 host 的特征合并到一起(全部合并为一列向量),并储存,此时 data_GAN.txt 代表了可以互作的 phage 和 host 全部的 dna 和 protein 特征(一列向量)
np.savetxt('/home/phiaf/result/data_GAN.txt', np.concatenate((phage_all, host_all), axis=1))

此时 data_GAN.txt 代表了可以互作的 phage 和 host 全部的 dna 和 protein 特征(一列向量)

step 2:生成pseudo数据:

data = inf_train_gen('data_GAN')
FIXED_GENERATOR = False
LAMBDA = .1
CRITIC_ITERS = 5
BATCH_SIZE = len(data)
ITERS = 10000
use_cuda = False

## 实例化一个对象,生成 G 网络
netG = Generator(data.shape[1])
netD = Discriminator(data.shape[1])
netD.apply(weights_init)
netG.apply(weights_init)

optimizerD = optim.Adam(netD.parameters(), lr=1e-4, betas=(0.5, 0.9))
optimizerG = optim.Adam(netG.parameters(), lr=1e-4, betas=(0.5, 0.9))
one = torch.tensor(1, dtype=torch.float)  ###torch.FloatTensor([1])
mone = one * -1


for iteration in range(ITERS):
    print(iteration)
    for p in netD.parameters():
        # 要求每一轮运算完成需要更新权重参数,使得预测值与真实值的误差尽可能小
        ## requires_grad=True 的作用是让 backward 可以追踪这个参数并且计算它的梯度, 与计算损失函数的链式求导有关(参与误差反向传播, 要不要计算梯度)
        p.requires_grad = True
    ## 读取可以互作的 phage 和 host 全部的 dna 和 protein 特征(一列向量), data_GAN.txt
    data = inf_train_gen('data_GAN')
    ## 将 data_GAN.txt 转换成 torch 语法的 tensor
    real_data = torch.FloatTensor(data)

    # 定义一个 Variable 存放 data_GAN.txt 变量,real_data_v 为真实的正样本
    real_data_v = autograd.Variable(real_data)
    # 随机生成一个张量 (1 行 864 列的张量),正态分布均值为0,方差为1,即高斯白噪声
    noise = torch.randn(BATCH_SIZE, data.shape[1])
    # 定义一个 Variable 存放 noise 变量
    noisev = autograd.Variable(noise, volatile=True)
    # 定义一个 Variable 存放生成的 pseudo 数据
    fake = autograd.Variable(netG(noisev).data)
    # 将 pseudo 数据转换为矩阵
    fake_output=fake.data.cpu().numpy()

    ## 训练判别器 netD()
    for iter_d in range(CRITIC_ITERS):
        #  netD 梯度清零
        netD.zero_grad()
        # 判别器 netD() 读取真实的正样本数据,并生成一列结果向量
        D_real = netD(real_data_v)
        # 转换为均值
        D_real = D_real.mean()


        # 随机生成一个噪声张量 (1 行 864 列的张量),正态分布均值为0,方差为1,即高斯白噪声
        noise = torch.randn(BATCH_SIZE, data.shape[1])
        # 定义一个 Variable 存放随机生成的数据(向量),1 行 864 列的张量可以理解为有 a1 ...... a864 个变量( 见 tip 5)
        noisev = autograd.Variable(noise, volatile=True)
        # 定义一个 Variable 存放生成的 pseudo 数据,pseudo 数据是由生成器 netG 基于随机向量 noisev 生成
        fake = autograd.Variable(netG(noisev).data)
        inputv = fake
        ##  判别器 netD() 读取生成器 netG 生成的 pseudo 数据,并生成一列结果向量
        D_fake = netD(inputv)
        ## 转换为均值
        D_fake = D_fake.mean()

        ## 计算惩罚项
        gradient_penalty = calc_gradient_penalty(netD, real_data_v.data, fake.data)
       ## 计算损失函数,目的是使得 pseudo 数据 D_fake 与真实数据 D_real 的误差缩小
        D_cost = D_fake - D_real + gradient_penalty
        Wasserstein_D = D_real - D_fake
        D_cost.backward()
        # 对优化器参数进行更新
        optimizerD.step()

    ## 训练生成器 netG
    if not FIXED_GENERATOR:
        for p in netD.parameters():
            p.requires_grad = False
        netG.zero_grad()
        
        # 读取真实的正样本数据
        real_data = torch.Tensor(data)        
        real_data_v = autograd.Variable(real_data)
        ## 转换为均值
        real_data_v_G = real_data_v.mean()
          
        # 随机生成一列向量
        noise = torch.randn(BATCH_SIZE, data.shape[1])
        # 基于随机生成一列向量构造 pseudo 数据 fake
        noisev = autograd.Variable(noise)
        fake = netG(noisev)
        # 由判别器 netD 判断 pseudo 数据 fake,判别器 netD 将会计算出一列结果向量 G
        G = netD(fake)
        G = G.mean()

        ## 构造损失函数
        G_cost = G -  real_data_v_G
        ## 反向传播
        G_cost.backward()
        optimizerG.step()

    ###save generated sample features every 200 iteration
    if iteration%200 == 0:
        fake_writer = open("/home/phiaf/result/Iteration_"+str(iteration)+".txt","w")
        for rowIndex in range(len(fake_output)):
            for columnIndex in range(len(fake_output[0])):
                fake_writer.write(str(fake_output[rowIndex][columnIndex]) + ",")
            fake_writer.write("\n")
        fake_writer.flush()
        fake_writer.close()

requires_grad=True 的解释 的作用是让 backward 可以追踪这个参数并且计算它的梯度, 与计算损失函数的链式求导有关(参与误差反向传播, 要不要计算梯度)

这个例子中作者将判别器 netD 的损失函数定义为 D_fake - D_real + gradient_penalty,其中 D_fake 和 D_real 为将一列向量的元素均值化后的值(标量),gradient_penalty 为惩罚项(标量),D_fake 为判别器 netD 基于伪数据生成的结果,D_real 为为真实的正样本结果,而判别器 netD 的目的是能够更加精细的区分伪数据和真实正样本
生成器 netG 的损失函数定义为 G_cost = G - real_data_v_G,其中 G 和 real_data_v_G 为将一列向量的元素均值化后的值(标量),G 为判别器 netD 基于伪数据生成的结果,real_data_v_G 为真实的正样本结果,生成器 netG 的目的是能够尽可能使产生的伪数据接近真实正样本,以骗过判别器 netD 的判断

step 3 检验生成的伪数据的真实性:

####test model result, LOOCV to select optimal pseudo samples
with open("../result/result_GAN/data_GAN.txt") as f:
    MatrixFeatures = [list(x.split(" ")) for x in f]
realFeatures = [line[:] for line in MatrixFeatures[:]]
realDataset = np.array(realFeatures, dtype='float32')
# Adding equal numbers of binary labels
label=[]
for rowIndex in range(len(realDataset)):
    label.append(1)
for rowIndex in range(len(realDataset)):
    label.append(0)
labelArray=np.asarray(label)
opt_diff_accuracy_05=0.5
opt_Epoch=0
opt_accuracy=0
allresult=[]
for indexEpoch in range(500):
    epoch = indexEpoch * 200
    with open("../result/result_GAN/Iteration_"+str(epoch)+".txt") as f:
          MatrixFeatures = [list(x.split(",")) for x in f]
    fakeFeatures = [line[:-1] for line in MatrixFeatures[:]]
    fakedataset = np.array(fakeFeatures, dtype='float32')
    realFakeFeatures=np.vstack((realDataset, fakedataset))

    prediction_list=[]
    real_list=[]
    ####LOOCV
    loo = LeaveOneOut()
    loo.get_n_splits(realFakeFeatures)
    for train_index, test_index in loo.split(realFakeFeatures):
        X_train, X_test = realFakeFeatures[train_index], realFakeFeatures[test_index]
        y_train, y_test = labelArray[train_index], labelArray[test_index]
        knn = KNeighborsClassifier(n_neighbors=1).fit(X_train, y_train)
        predicted_y = knn.predict(X_test)
        prediction_list.append(predicted_y)
        real_list.append(y_test)
    accuracy=accuracy_score(real_list, prediction_list)
    allresult.append(str(indexEpoch)+"%"+str(accuracy))
    diff_accuracy_05=abs(accuracy-0.5)
    if diff_accuracy_05 < opt_diff_accuracy_05:
        opt_diff_accuracy_05=diff_accuracy_05
        opt_Epoch=epoch
        opt_accuracy=accuracy
print(str(opt_Epoch)+"%"+str(opt_accuracy))

由于每训练200轮,将会输出伪数据,这一步的目的是检测输出的所有伪数据哪一些更接近真实的正样本

小tips

[1]. 实例化生成模型(基于pytorch语法)
class Generator(nn.Module):
    def __init__(self, shape1):
        super(Generator, self).__init__()
        main = nn.Sequential(
            nn.Linear(shape1, 128),
            nn.ReLU(True),
            nn.Linear(128, 256),
            nn.ReLU(True),
            nn.Linear(256, 512),
            nn.ReLU(True),
            nn.Linear(512, 1024),
            nn.Tanh(),
            nn.Linear(1024, shape1),
        )
        self.main = main

    def forward(self, noise, real_data):
         output = self.main(noise)
         return output

## 实例化 G 网络
netG = Generator(data.shape[1])
netD.apply(weights_init)

# 计算
netG(noisev, real_data_v)
# 等价于
netG.forward(noisev, real_data_v)

事实上netG(noisev)netG.forward(noisev),当传入数据noisevreal_data_v时执行的是:

 main = nn.Sequential(
            nn.Linear(shape1, 128),
            nn.ReLU(True),
            nn.Linear(128, 256),
            nn.ReLU(True),
            nn.Linear(256, 512),
            nn.ReLU(True),
            nn.Linear(512, 1024),
            nn.Tanh(),
            nn.Linear(1024, shape1),
        )

其中:

class Generator(nn.Module):
    def __init__(self, shape1):
        super(Generator, self).__init__()
        main = nn.Sequential(
            nn.Linear(shape1, 128),
            nn.ReLU(True),
            nn.Linear(128, 256),
            nn.ReLU(True),
            nn.Linear(256, 512),
            nn.ReLU(True),
            nn.Linear(512, 1024),
            nn.Tanh(),
            nn.Linear(1024, shape1),
        )
        # 执行 main 函数
        self.main = main

    def forward(self, noise):
        output = self.main(noise)
        return output

# self.main = main 代表执行 main 函数
[2]. 生成模型 netG 结构
netG = Generator(data.shape[1])
netG.apply(weights_init)

print(netG)
print(list(netG.parameters()))

netG 的结构以及每一层结构对应的初始化权重参数:

# netG 结构
Generator(
  (main): Sequential(
    (0): Linear(in_features=864, out_features=128, bias=True)
    (1): ReLU(inplace=True)
    (2): Linear(in_features=128, out_features=256, bias=True)
    (3): ReLU(inplace=True)
    (4): Linear(in_features=256, out_features=512, bias=True)
    (5): ReLU(inplace=True)
    (6): Linear(in_features=512, out_features=1024, bias=True)
    (7): Tanh()
    (8): Linear(in_features=1024, out_features=864, bias=True)
  )
)

# 每一层结构对应的初始化权重参数
Parameter containing:
## Linear(in_features=864, out_features=128, bias=True)
tensor([[ 1.2168e-02,  2.7353e-02, -2.8277e-02,  ...,  3.2443e-02,
          1.5985e-02,  1.2108e-02],
        [-7.0914e-03,  9.4568e-03,  1.0394e-02,  ..., -1.8338e-02,
          3.2946e-03,  2.6501e-02],
        [ 1.4687e-02, -1.5824e-02,  7.3161e-03,  ..., -1.7613e-02,
          1.1925e-02, -1.0545e-02],
        ...,
        [-8.8383e-03,  1.6274e-02, -2.6005e-02,  ...,  4.1564e-03,
         -9.5081e-03,  2.6123e-02],
        [ 1.1470e-02,  1.8002e-02,  1.0864e-02,  ...,  4.7736e-03,
          2.2449e-02,  1.4833e-02],
        [-1.7769e-02,  3.5312e-03, -4.9738e-03,  ..., -3.7618e-05,
         -1.9576e-03, -1.5175e-02]], requires_grad=True), 

Parameter containing:
## ReLU(inplace=True)
tensor([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0.], requires_grad=True), 

Parameter containing:
## Linear(in_features=128, out_features=256, bias=True)
tensor([[-0.0110, -0.0047, -0.0027,  ...,  0.0064, -0.0110, -0.0324],
        [-0.0061, -0.0023,  0.0250,  ...,  0.0150,  0.0245,  0.0244],
        [ 0.0337,  0.0291,  0.0137,  ..., -0.0081,  0.0202,  0.0076],
        ...,
        [-0.0120, -0.0140, -0.0303,  ...,  0.0014, -0.0031, -0.0026],
        [ 0.0397,  0.0014,  0.0304,  ...,  0.0357,  0.0148,  0.0075],
        [ 0.0048, -0.0095,  0.0259,  ..., -0.0096, -0.0033, -0.0228]],
       requires_grad=True), 

Parameter containing:
##  ReLU(inplace=True)
tensor([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       requires_grad=True), 

Parameter containing:
## Linear(in_features=256, out_features=512, bias=True)
tensor([[-0.0268, -0.0256, -0.0018,  ..., -0.0122,  0.0229, -0.0120],
        [-0.0108, -0.0052, -0.0068,  ..., -0.0083, -0.0047, -0.0065],
        [-0.0063,  0.0129,  0.0254,  ..., -0.0007, -0.0366,  0.0254],
        ...,
        [ 0.0277, -0.0060, -0.0177,  ..., -0.0341, -0.0216, -0.0029],
        [-0.0086,  0.0132,  0.0023,  ...,  0.0351, -0.0320, -0.0139],
        [ 0.0134,  0.0028,  0.0324,  ..., -0.0345, -0.0102, -0.0134]],
       requires_grad=True), 

Parameter containing:
## ReLU(inplace=True)
tensor([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0.], requires_grad=True), 

Parameter containing:
## Linear(in_features=512, out_features=1024, bias=True)
tensor([[-5.3577e-03,  2.1187e-02, -2.2485e-04,  ..., -7.8326e-03,
         -1.8492e-02, -3.6416e-02],
        [-2.6918e-02, -1.3238e-02,  2.0151e-02,  ..., -1.5236e-02,
         -3.0986e-02,  2.2858e-02],
        [ 1.4550e-02, -2.4193e-02,  3.8080e-03,  ..., -1.0529e-02,
          3.5056e-02, -2.2059e-02],
        ...,
        [ 1.4448e-03,  8.5981e-03, -1.6759e-02,  ..., -2.5140e-02,
         -1.8255e-03,  2.2529e-02],
        [ 5.2836e-02,  1.0386e-02,  3.1571e-03,  ...,  1.7078e-02,
         -7.2594e-03, -9.8481e-05],
        [ 3.8155e-02,  2.8551e-02,  3.2344e-02,  ...,  1.6333e-02,
          9.4571e-03, -1.7940e-02]], requires_grad=True), 

Parameter containing:
## Tanh()
tensor([0., 0., 0.,  ..., 0., 0., 0.], requires_grad=True), Parameter containing:
tensor([[ 0.0008, -0.0073, -0.0042,  ...,  0.0212, -0.0095, -0.0055],
        [-0.0201,  0.0373, -0.0154,  ...,  0.0138, -0.0221, -0.0035],
        [ 0.0181, -0.0185,  0.0333,  ..., -0.0085, -0.0107, -0.0146],
        ...,
        [ 0.0038,  0.0019,  0.0083,  ..., -0.0050, -0.0071,  0.0334],
        [-0.0236,  0.0136,  0.0231,  ..., -0.0035,  0.0250, -0.0042],
        [-0.0132, -0.0127,  0.0002,  ..., -0.0085,  0.0274, -0.0171]],
       requires_grad=True), 

Parameter containing:
## Linear(in_features=1024, out_features=864, bias=True)
tensor([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
       requires_grad=True)

显而易见,本例子中的生成模型 netG 一共有 8 层

[3]. 初始化模型每一层的权重参数

注意到:

# 定义生成模型 netG 和判别模型 netD 每一层的初始化权重参数
def weights_init(m):
    classname = m.__class__.__name__
    ## 对每一层全连接层 Linear 的权重进行初始化
    if classname.find('Linear') != -1:
        m.weight.data.normal_(0.0, 0.02)
        m.bias.data.fill_(0)
    elif classname.find('BatchNorm') != -1:
        m.weight.data.normal_(1.0, 0.02)
        m.bias.data.fill_(0)

作者在这里定义了对每一层全连接层 Linear 的权重进行初始化

所有的层:

  1. Discriminator:Linear,LeakyReLU,Linear,Linear,Linear
  2. Generator:Linear,ReLU,Linear,ReLU,Linear,ReLU,Linear,Tanh,Linear
[4]. 定义容器存放变量
real_data_v = autograd.Variable(real_data)
noisev = autograd.Variable(noise, volatile=True)
fake = autograd.Variable(netG(noisev).data)

Variable 的作用是定义一个容器存放变量,用作 pytorch 每一轮运算更新存入变量用


[5]. backward 用法
a = torch.randn(1, 10)
a = autograd.Variable(a,requires_grad = True)

one = torch.tensor(1, dtype=torch.float)
b = a.mean()
b.backward(one)

print(a)
print(a[0,2])
print(b)
print(one)
print(b.data)
print(a.grad)

# result
tensor([[ 0.6614,  0.2669,  0.0617,  0.6213, -0.4519, -0.1661, -1.5228,  0.3817,
         -1.0276, -0.5631]], requires_grad=True)
tensor(0.0617, grad_fn=<SelectBackward0>)
tensor(-0.1739, grad_fn=<MeanBackward0>)
tensor(1.)
tensor(-0.1739)
tensor([[0.1000, 0.1000, 0.1000, 0.1000, 0.1000, 0.1000, 0.1000, 0.1000, 0.1000,
         0.1000]])

上述例子求导过程:
将变量 a 的元素想象成变量,该例子一共 a1,a2,a3.........a10个变量,b = a.mean() 代表构造函数 f = (a1+a2+a3+.........+a10) / 10,然后利用函数 f 依次对a1,a2,a3.........a10求偏导,所得的偏导结果任然为一列向量 tensor([[0.1000, 0.1000, 0.1000, 0.1000, 0.1000, 0.1000, 0.1000, 0.1000, 0.1000,0.1000]])

作为backward的参数one,one = tensor(1.) 意思是利用函数 f 依次对a1,a2,a3.........a10求偏导的结果保存为一列向量(向量维度为变量 an 数)

若:

a = torch.randn(1, 10)
a = autograd.Variable(a,requires_grad = True)

one = torch.tensor(1, dtype=torch.float)
mone = one * -1
b = a.mean()
b.backward(mone)

print(a.grad)

# result
tensor([[-0.1000, -0.1000, -0.1000, -0.1000, -0.1000, -0.1000, -0.1000, -0.1000,
         -0.1000, -0.1000]])

如果backward的参数one,one = tensor(-1.),意味着利用函数 f 依次对a1,a2,a3.........a10求偏导的结果保存为一列向量(向量维度为变量 an 数),它的结果取相反数

其他例子参考:https://www.cnblogs.com/JeasonIsCoding/p/10164948.html

[6]. 关于生成器 G 生成数据的取值范围

关于生成器 G 生成 fake 数据的值域问题,这个 fake 值域问题取决于 real 的值域,GAN 的目的是使得 fake 向量与 real 向量尽量相似,因此如果 real 的值域介于 0-1 ,那么生成器 G 的最后一层可以加一个sigmoid函数;如果 real 的值域为正数 ,那么生成器 G 的最后一层可以加一个relu函数;如果 real 的值域为正数 ,那么生成器 G 的最后一层可以加一个relu函数;如果 real 的值域为--1 到 1 ,那么生成器 G 的最后一层可以加一个tanh函数

一般来说,初始化的生成器 G 和判别器 D 需要对 linear 层进行参数的初始化( Y = X·W + b,初始化参数 W)否则参数可能为 NA。

def weights_init(m):
    classname = m.__class__.__name__
    if classname.find('Linear') != -1:
        m.weight.data.normal_(0.0, 0.02)
        m.bias.data.fill_(0)
    elif classname.find('BatchNorm') != -1:
        m.weight.data.normal_(1.0, 0.02)
        m.bias.data.fill_(0)

# 对 W 进行初始化
m.weight.data.normal_(0.0, 0.02)
# 对截距 b 进行初始化
m.bias.data.fill_(0)

神经网络的结构通常是一层线性函数(linear)加一层非线性函数(relu,sigmoid,tanh),否则相当于只有一层,神经网络结构(以Relu与linear为例,嵌套):


上一篇下一篇

猜你喜欢

热点阅读