Download scripts/train.py from OneScience-Group/UTRGAN: direct link, hf CLI and curl.
- Browser
- Download file 13.4 kB
-
https://huggingface.co/OneScience-Group/UTRGAN/resolve/main/scripts/train.py
- Command line
-
hf download hf://OneScience-Group/UTRGAN/scripts/train.py
-
curl -L -o train.py https://huggingface.co/OneScience-Group/UTRGAN/resolve/main/scripts/train.py
13.4 kB
| import os | |
| import sys | |
| from pathlib import Path | |
| # Keep the official ``src`` package importable after adopting the standard | |
| # conf/model/scripts/weight layout. | |
| PROJECT_ROOT = Path(__file__).resolve().parents[1] | |
| MODEL_ROOT = PROJECT_ROOT / "model" | |
| if str(MODEL_ROOT) not in sys.path: | |
| sys.path.insert(0, str(MODEL_ROOT)) | |
| # The released H5 files use the legacy Keras serialization format. | |
| os.environ.setdefault("TF_USE_LEGACY_KERAS", "1") | |
| import numpy as np | |
| import pandas as pd | |
| import pdb | |
| import tensorflow as tf | |
| # from IPython.display import clear_output | |
| import time | |
| from src.gan.lib import models | |
| from src.gan.lib import utils | |
| import socket | |
| import datetime | |
| from tqdm import tqdm | |
| import random | |
| import matplotlib.pyplot as plt | |
| import argparse | |
| import tensorflow.keras.backend as K | |
| from tensorflow.keras.optimizers import Adam | |
| tf.compat.v1.enable_eager_execution() | |
| parser = argparse.ArgumentParser() | |
| parser.add_argument('-d', type=str, required=False, | |
| default=str(PROJECT_ROOT / 'conf' / 'data' / 'utrdb2.csv')) | |
| parser.add_argument('-bs', type=int, required=False ,default=64) | |
| parser.add_argument('-lr', type=int, required=False ,default=5) | |
| parser.add_argument('-mil', type=int, required=False ,default=64) | |
| parser.add_argument('-mxl', type=int, required=False ,default=128) | |
| parser.add_argument('-dim', type=int, required=False ,default=40) | |
| parser.add_argument('-gpu', type=str, required=False ,default='-1') | |
| parser.add_argument('-e', '--epochs', type=int, default=4000, | |
| help='Number of complete passes over the filtered UTRdb dataset.') | |
| parser.add_argument('--output-dir', type=str, | |
| default=str(PROJECT_ROOT / 'outputs' / 'train'), | |
| help='Directory for logs, generated samples, and checkpoints.') | |
| args = parser.parse_args() | |
| MODEL_NAME = 'WGAN-TF2' | |
| RUN_ROOT = Path(args.output_dir).expanduser().resolve() | |
| OUTPUT_PATH = RUN_ROOT / 'outputs' / MODEL_NAME | |
| TRAIN_LOGDIR = RUN_ROOT / 'tensorboard' / MODEL_NAME / 'train_data' | |
| OUTPUT_PATH.mkdir(parents=True, exist_ok=True) | |
| TRAIN_LOGDIR.mkdir(parents=True, exist_ok=True) | |
| file_writer = tf.summary.create_file_writer(str(TRAIN_LOGDIR)) | |
| if args.gpu == '-1': | |
| device = 'cpu' | |
| else: | |
| os.environ['CUDA_VISIBLE_DEVICES'] = args.gpu | |
| device = 'cuda' | |
| def plot(x, y, logdir, name, xlabel=None, ylabel=None, title=None): | |
| plt.plot(x,y,'-') | |
| plt.title(title) | |
| plt.xlabel(xlabel) | |
| plt.ylabel(ylabel) | |
| plt.savefig(logdir+'/'+name+'.png') | |
| plt.clf() | |
| def plot_valid(x1, y1, x2, y2, logdir, name, xlabel=None, ylabel=None, title=None): | |
| plt.plot(x2,y2,'-',color='tab:blue') | |
| plt.plot(x1,y1,'-',color='tab:orange') | |
| plt.title(title) | |
| plt.xlabel(xlabel) | |
| plt.ylabel(ylabel) | |
| plt.savefig(logdir+'/'+name+'.png') | |
| plt.clf() | |
| def gradient_penalty_loss( y_true, y_pred, discriminator): | |
| """ | |
| Computes gradient penalty based on prediction and weighted real / fake samples | |
| """ | |
| alpha = K.random_uniform((DIM, 1, 1)) | |
| averaged_samples = (alpha * y_pred) + ((1 - alpha) * y_true) | |
| gradients = K.gradients(y_pred, averaged_samples)[0] | |
| # compute the euclidean norm by squaring ... | |
| gradients_sqr = K.square(gradients) | |
| # ... summing over the rows ... | |
| gradients_sqr_sum = K.sum(gradients_sqr, | |
| axis=np.arange(1, len(gradients_sqr.shape))) | |
| # ... and sqrt | |
| gradient_l2_norm = K.sqrt(gradients_sqr_sum) | |
| # compute lambda * (1 - ||grad||)^2 still for each single sample | |
| gradient_penalty = K.square(1 - gradient_l2_norm) | |
| # return the mean as loss over all the batch samples | |
| return K.mean(gradient_penalty) | |
| def log(samples_dir=False,suff=None): | |
| stamp = datetime.date.strftime(datetime.datetime.now(), "%Y.%m.%d-%Hh%Mm%Ss") + "_{}".format(socket.gethostname()) | |
| full_logdir = os.path.join(str(RUN_ROOT / "logs"), stamp) | |
| if suff: | |
| full_logdir = full_logdir + suff | |
| os.makedirs(full_logdir, exist_ok=True) | |
| if samples_dir: os.makedirs(os.path.join(full_logdir, "samples"), exist_ok=True) | |
| log_dir = "{}:{}".format(socket.gethostname(), full_logdir) | |
| return full_logdir, 0 | |
| data_path = args.d | |
| data_utr = pd.read_csv(data_path) | |
| UTRdf = data_utr['seq'].to_numpy() | |
| seqs = [] | |
| UTR_LEN = args.mxl | |
| for i in range(len(UTRdf)): | |
| if len(UTRdf[i]) < UTR_LEN+1 and len(UTRdf[i]) > int(UTR_LEN/2): | |
| if UTRdf[i] not in seqs: | |
| seqs.append(UTRdf[i]) | |
| sequences = np.array(seqs) | |
| sequences = [x.upper() for x in sequences] | |
| rna_vocab = {"A":0, | |
| "C":1, | |
| "G":2, | |
| "U":3, | |
| "*":4} | |
| rev_rna_vocab = {v:k for k,v in rna_vocab.items()} | |
| def one_hot_encode(seq, SEQ_LEN=UTR_LEN): | |
| mapping = dict(zip("ACGT*", range(5))) | |
| seq2 = [mapping[i] for i in seq] | |
| if len(seq2) < SEQ_LEN: | |
| extra = [np.eye(5)[4]] * (SEQ_LEN - len(seq2)) | |
| return np.vstack([np.eye(5)[seq2] , extra]) | |
| return np.eye(5)[seq2] | |
| def one_hot_encode_2(seq, SEQ_LEN=UTR_LEN): | |
| mapping = dict(zip("ACGT", range(4))) | |
| seq2 = [mapping[i] for i in seq] | |
| return np.eye(4)[seq2] | |
| ohe_sequences = np.asarray([one_hot_encode(x) for x in sequences]) | |
| BATCH_SIZE = args.bs # Batch size | |
| ITERS = args.epochs # How many complete dataset iterations to train for | |
| SEQ_LEN = UTR_LEN # Sequence length in characters | |
| DIM = args.dim # Model dimensionality. | |
| CRITIC_ITERS = 5 # How many critic iterations per generator iteration. | |
| LAMBDA = 10 # Gradient penalty lambda hyperparameter. | |
| # README defines ``-lr 5`` as 1e-5. The upstream ``e**args.lr`` expression | |
| # is inconsistent with that documented interface. | |
| LR = np.power(10.0, -args.lr) | |
| LAMBDA = 10 # For gradient penalty | |
| CURRENT_EPOCH = 1 # Epoch start from | |
| SAVE_EVERY_N_EPOCH = 50 # Save checkpoint at every n epoch | |
| MIN_LR = 0.000001 # Minimum value of learning rate | |
| DECAY_FACTOR=1.00004 # learning rate decay factor | |
| ''' | |
| Set seed for reproducibility | |
| ''' | |
| seed = 35 | |
| np.random.seed(seed) | |
| # tf.set_random_seed(seed) | |
| tf.random.set_seed(seed) | |
| logdir, checkpoint_baseline = log(samples_dir=True) | |
| logdir2 = '' | |
| ''' | |
| Build GAN | |
| ''' | |
| model_type = "resnet" | |
| data_enc_dim = 5 | |
| data_size = SEQ_LEN * data_enc_dim | |
| # data_size = 256 | |
| gen_layers = 3 | |
| disc_layers = 3 | |
| lmbda = 10. #lipschitz penalty hyperparameter. | |
| SAMPLE_SIZE = 128 | |
| N_CHANNELS = DIM | |
| G = models.resnet_g2(DIM,N_CHANNELS,SEQ_LEN,5,res_layers=gen_layers) | |
| D = models.resnet_d2(N_CHANNELS,SEQ_LEN,5,res_layers=disc_layers) | |
| G.summary() | |
| D.summary() | |
| D_optimizer = Adam(learning_rate=LR, beta_1=0.5, beta_2=0.99) | |
| G_optimizer = Adam(learning_rate=LR, beta_1=0.5, beta_2=0.99) | |
| EPOCHs = ITERS | |
| def WGAN_GP_train_d_step(real_sample, batch_size, step): | |
| noise = tf.random.normal([batch_size, DIM]) | |
| epsilon = tf.random.uniform(shape=[batch_size, 1, 1], minval=0, maxval=1) | |
| ################################### | |
| # Train D | |
| ################################### | |
| with tf.GradientTape(persistent=True) as d_tape: | |
| with tf.GradientTape() as gp_tape: | |
| fake_sample = G([noise], training=True) | |
| fake_sample_mixed = epsilon * tf.dtypes.cast(real_sample, tf.float32) + ((1 - epsilon) * fake_sample) | |
| fake_mixed_pred = D([fake_sample_mixed], training=True) | |
| # Compute gradient penalty | |
| grads = gp_tape.gradient(fake_mixed_pred, fake_sample_mixed) | |
| grad_norms = tf.sqrt(tf.reduce_sum(tf.square(grads), axis=[1,2])) # Originally axis=[1,2] | |
| # grad_norms = tf.norm(grads, axis=[1,2]) | |
| gradient_penalty = tf.reduce_mean(tf.square(grad_norms - 1.)) | |
| fake_pred = D([fake_sample], training=True) | |
| real_pred = D([real_sample], training=True) | |
| D_loss = tf.reduce_mean(fake_pred) - tf.reduce_mean(real_pred) + LAMBDA * gradient_penalty | |
| # Calculate the gradients for discriminator | |
| D_gradients = d_tape.gradient(D_loss,D.trainable_variables) | |
| # Apply the gradients to the optimizer | |
| D_optimizer.apply_gradients(zip(D_gradients,D.trainable_variables)) | |
| # Write loss values to tensorboard | |
| if step % 10 == 0: | |
| with file_writer.as_default(): | |
| tf.summary.scalar('D_loss', tf.reduce_mean(D_loss), step=step) | |
| return D_loss, gradient_penalty | |
| def WGAN_GP_train_g_step(real_sample, batch_size, step): | |
| noise = tf.random.normal([batch_size, DIM]) | |
| ################################### | |
| # Train G | |
| ################################### | |
| with tf.GradientTape() as g_tape: | |
| fake_sample = G([noise], training=True) | |
| fake_pred = D([fake_sample], training=True) | |
| G_loss = -tf.reduce_mean(fake_pred) | |
| G_gradients = g_tape.gradient(G_loss, | |
| G.trainable_variables) | |
| # Apply the gradients to the optimizer | |
| G_optimizer.apply_gradients(zip(G_gradients, | |
| G.trainable_variables)) | |
| # Write loss values to tensorboard | |
| if step % 10 == 0: | |
| with file_writer.as_default(): | |
| tf.summary.scalar('G_loss', G_loss, step=step) | |
| return G_loss, noise | |
| checkpoint_path = os.path.join(str(RUN_ROOT), "checkpoints", "tensorflow", MODEL_NAME) | |
| ckpt = tf.train.Checkpoint(generator=G, | |
| discriminator=D, | |
| G_optimizer=G_optimizer, | |
| D_optimizer=D_optimizer) | |
| ckpt_manager = tf.train.CheckpointManager(ckpt, checkpoint_path, max_to_keep=40) | |
| def generate_and_save_samples(model, epoch, test_input, figure_size=(12,6), subplot=(3,6), save=True, is_flatten=False): | |
| ''' | |
| Generate samples and plot it. | |
| ''' | |
| predictions = model.predict(test_input) | |
| utils.save_samples(logdir, predictions, epoch, rev_rna_vocab, annotated=False) | |
| ''' | |
| load data | |
| ''' | |
| Train = True | |
| validate = True | |
| data = ohe_sequences | |
| if validate: | |
| split = len(data) // 10 | |
| # print(split) | |
| valid_data = data[:split] | |
| train_data = data[split:] | |
| if len(train_data) == 1: train_data = train_data[0] | |
| if len(valid_data) == 1: valid_data = valid_data[0] | |
| else: | |
| train_data = data | |
| train_data = train_data.astype('float32') | |
| valid_data = valid_data.astype('float32') | |
| train_seqs = tf.data.Dataset.from_tensor_slices(train_data).shuffle(len(train_data)).batch(BATCH_SIZE) | |
| valid_seqs = tf.data.Dataset.from_tensor_slices(valid_data).shuffle(len(valid_data)).batch(split) | |
| plot_iter = 10 | |
| current_learning_rate = LR | |
| trace = True | |
| n_critic_count = 0 | |
| d_losses = [] | |
| g_losses = [] | |
| gradient_penalties = [] | |
| iterations = 0 | |
| iteration_numbers = [] | |
| iteration_numbers_valid = [] | |
| d_validation_losses = [] | |
| random_name = time.strftime("%Y%m%d-%H%M%S") | |
| gen_iters = 0 | |
| if Train: | |
| sample_noise = tf.random.normal([BATCH_SIZE, DIM]) | |
| generate_and_save_samples(G, 0, [sample_noise], figure_size=(12,6), subplot=(3,6), save=False, is_flatten=False) | |
| pbar = tqdm(range(EPOCHs)) | |
| for epoch in pbar: | |
| start = time.time() | |
| tdataset = train_seqs.enumerate() | |
| for step, tdata in tdataset.as_numpy_iterator(): | |
| current_batch_size = tdata.shape[0] | |
| d_loss, gp = WGAN_GP_train_d_step(tdata, batch_size=tf.constant(current_batch_size, dtype=tf.int64), step=tf.constant(step, dtype=tf.int64)) | |
| n_critic_count += 1 | |
| if n_critic_count >= CRITIC_ITERS: | |
| g_loss, noise = WGAN_GP_train_g_step(tdata, batch_size= tf.constant(current_batch_size, dtype=tf.int64), step=tf.constant(step, dtype=tf.int64)) | |
| gen_iters += 1 | |
| n_critic_count = 0 | |
| if step % 10 == 0: | |
| print ('.', end='') | |
| if epoch % SAVE_EVERY_N_EPOCH == 0 and epoch != 0: | |
| ckpt_save_path = ckpt_manager.save() | |
| utils.save_checkpoints(logdir,G,epoch) | |
| if epoch % 50 == 0: | |
| generate_and_save_samples(G, epoch, [sample_noise], figure_size=(12,6), subplot=(3,6), save=True, is_flatten=False) | |
| os.system('clear') | |
| iteration_numbers.append(iterations) | |
| g_losses.append(-g_loss) | |
| d_losses.append(-d_loss) | |
| gradient_penalties.append(gp) | |
| # plot(iteration_numbers, d_losses, logdir, 'discriminator_loss', xlabel="Iteration", ylabel="Discriminator Cost") | |
| # plot(iteration_numbers, g_losses, logdir, 'generator_loss', xlabel="Iteration", ylabel="Generator Cost") | |
| # plot(iteration_numbers, gradient_penalties, logdir, 'gradient_penalty', xlabel="Iteration", ylabel="Gradient Penalty") | |
| iterations+=1 | |
| iteration_numbers_valid.append(iterations) | |
| fake_sample_valid = G([noise], training=True) | |
| fake_pred_valid = D([fake_sample_valid], training=True) | |
| real_pred_valid = D([tf.convert_to_tensor(list(valid_seqs.as_numpy_iterator())[0])], training=True) | |
| D_loss_valid = tf.reduce_mean(fake_pred_valid) - tf.reduce_mean(real_pred_valid) | |
| d_validation_losses.append(-D_loss_valid) | |
| # plot_valid(iteration_numbers_valid, d_validation_losses, iteration_numbers, d_losses, logdir, 'validation_loss', xlabel="Iteration", ylabel="D Validation Loss") | |
| ckpt_save_path = ckpt_manager.save() | |
| print ('Saving checkpoint for epoch {} at {}'.format(EPOCHs, | |
| ckpt_save_path)) | |
| print("####################################################") | |
| print(f"############### Gen Iterations : {gen_iters} #####") | |
| print("####################################################") | |