code: import numpy as np
  import torch
  from sklearn.metrics import roc_auc_score
  from tqdm import tqdm
  import config as c
  from model import get_cs_flow_model, save_model, FeatureExtractor, nf_forward
  from utils import *
  
  
  def train(train_loader, test_loader):
      model = get_cs_flow_model()
      optimizer = torch.optim.Adam(model.parameters(), lr=c.lr_init, eps=1e-04, weight_decay=1e-5)
      model.to(c.device)
      if not c.pre_extracted:
          fe = FeatureExtractor()
          fe.eval()
          fe.to(c.device)
          for param in fe.parameters():
              param.requires_grad = False
  
      z_obs = Score_Observer('AUROC')
  
      for epoch in range(c.meta_epochs):
          # train some epochs
          model.train()
          if c.verbose:
              print(F'\nTrain epoch {epoch}')
          for sub_epoch in range(c.sub_epochs):
              train_loss = list()
              for i, data in enumerate(tqdm(train_loader, disable=c.hide_tqdm_bar)):
                  optimizer.zero_grad()
  
                  inputs, labels = preprocess_batch(data)  # move to device and reshape
                  if not c.pre_extracted:
                      inputs = fe(inputs)
  
                  z, jac = nf_forward(model, inputs)
  
                  loss = get_loss(z, jac)
                  train_loss.append(t2np(loss))
  
                  loss.backward()
                  norm = torch.nn.utils.clip_grad_norm_(model.parameters(), c.max_grad_norm)
                  optimizer.step()
  
              mean_train_loss = np.mean(train_loss)
              if c.verbose and epoch == 0 and sub_epoch % 4 == 0:
                  print('Epoch: {:d}.{:d} \t train loss: {:.4f}'.format(epoch, sub_epoch, mean_train_loss))
  
          # evaluate
          model.eval()
          if c.verbose:
              print('\nCompute loss and scores on test set:')
          test_loss = list()
          test_z = list()
          test_labels = list()
  
          with torch.no_grad():
              for i, data in enumerate(tqdm(test_loader, disable=c.hide_tqdm_bar)):
                  inputs, labels = preprocess_batch(data)
                  if not c.pre_extracted:
                      inputs = fe(inputs)
  
                  z, jac = nf_forward(model, inputs)
                  loss = get_loss(z, jac)
  
                  z_concat = t2np(concat_maps(z))
                  score = np.mean(z_concat ** 2, axis=(1, 2))
                  test_z.append(score)
                  test_loss.append(t2np(loss))
                  test_labels.append(t2np(labels))
  
          test_loss = np.mean(np.array(test_loss))
          if c.verbose:
              print('Epoch: {:d} \t test_loss: {:.4f}'.format(epoch, test_loss))
  
          test_labels = np.concatenate(test_labels)
          is_anomaly = np.array([0 if l == 0 else 1 for l in test_labels])
  
          anomaly_score = np.concatenate(test_z, axis=0)
          z_obs.update(roc_auc_score(is_anomaly, anomaly_score), epoch,
                       print_score=c.verbose or epoch == c.meta_epochs - 1)
  
      if c.save_model:
          model.to('cpu')
          save_model(model, c.modelname)
  
      return z_obs.max_score, z_obs.last, z_obs.min_loss_score
  
apis: torch.no_grad sklearn.metrics.roc_auc_score numpy.array numpy.concatenate numpy.mean