# Notebook from malariagen/ano-spp
Path: work/1_panel_design/test/20180223_amplicons_from_alignment.ipynb

## Extract potential amplicons from MAF alignment
* Iterate over chromosomal MAF alignments
* Find conserved parts of an alignment using sliding window approach
* Amplicons can also span non-conserved regions, these are further referenced as long
* Write amplicon MAFs and target coordinates as TSV

Parameter for alignment extraction are listed below.

## Next step - 20180309 - extract phylogenetic information for amplicons_____no_output_____

from Bio import AlignIO
import numpy as np_____no_output_____# Alignment filtering parameters
min_species = 21 # minimum number of species in alignment
min_aligned = 190 # minimum alignment length, also used as minimum amplicon length

min_conserved = 50 # minimum length of flanks with given conservation level - used for primer design and, if possible, target sites
max_xs = 0.1 # maximum proportion of indels (represented as X) in flanks
max_ns = 0.1 # maximum proportion of substitutions (represented as N) in flanks

max_insert = 100 # maximum length of non-conserved sequence between two conserved flanks

def seq_repr(alignment):
    '''
    Given multiple sequence alignment, return first sequence with Ns for ambiguous chars and X's for indels.'''
    seq = ''
    for i in range(alignment.get_alignment_length()):
        col = alignment[:, i]
        if '-' in col: # indel stronger than substitution
            seq += 'X'
        elif len(set(col)) == 1:
            seq += col[0]
        else:
            seq += 'N'
    return seq

def get_conserved_subsequences(seq, max_ns=0.1, max_xs=0.1, min_len=100):
    '''
    Given sequence, conservation (max_ns) and indel (max_xs) levels, and minimum subsequence length
    return list of tuples for the subsequences with given conservation level (overlapping regions merged).
    If no conserved subsequences found, return 'None'.'''
    slen = len(seq)
    if slen < min_len:
        return None

    def is_conserved(s, max_ns, max_xs):
        if s.count('N')/len(s) <= max_ns and s.count('X')/len(s) <= max_xs:
            return True
        else:
            return False
    cons_windows = [is_conserved(seq[i:i + min_len], max_ns, max_xs) for i in range(slen - min_len + 1)]
    if sum(cons_windows) == 0:
        return None

    cons_kernels = []
    in_kernel = False
    for i, cw in enumerate(cons_windows):
        if in_kernel:
            if cw == False:
                in_kernel = False
                cons_kernels.append(i + min_len)
        elif cw == True:
            cons_kernels.append(i)
            in_kernel = True
    if in_kernel:
        cons_kernels.append(i + min_len)

    # merge overlapping kernels
    merged_kernels = []
    for i in range(len(cons_kernels)//2):
        start = cons_kernels[i * 2]
        end = cons_kernels[i * 2 + 1]
        if not merged_kernels:
            merged_kernels.append((start, end))
        else:
            prev_start = merged_kernels[-1][0]
            prev_end = merged_kernels[-1][1]
            if prev_end >= start:
                upper_bound = max(prev_end, end)
                merged_kernels[-1] = (prev_start, upper_bound)  # replace by merged interval
            else:
                merged_kernels.append((start, end))

    return np.asarray(merged_kernels)

# functions test
# for alignment in AlignIO.parse("../../data/AgamP3_maf/chr2L.maf", "maf"):
#     if len(alignment) >= min_species and alignment.get_alignment_length() >= min_aligned:
#         seq = seq_repr(alignment)
#         cons = get_conserved_subsequences(seq, max_ns=max_ns, max_xs=max_xs, min_len=min_conserved)
#         if cons is not None: # conser
#             print(seq)
#             print(cons, cons[:,1] - cons[:,0])
#             breakXXXXXXXAGANANCTTATAATTAGCGNNTAATTTACNTTCGATNAATTGGCAGGGGCAAGCTNCGNNAANNAATCNTCNNNTTTATGNGGATTNNANNNATTCCANNGNNNCNGNNTCGGTAAGTACGACNCCNNNNTCNANNNNNCNNGNNGANNNNNNNGANACNATNAANACTACNACNCCNNANGNAANNTNTGGGANTGNTGCTGACAGATGNTATGCATNNGNNCNNCTNCCGNNCANCNNGANNCNNTNTGNAANCGNTANCNNACNTTNCGNNNNCNNGGNNANXXXXXXNNNNGGNNTNNGNCCNAGNNTNGAGATGNGNNTNGCNNTNAANCACGNNATNCTNGNNGACGAAGANCTNNTCNCNTACAGNNCNGGNCCNGANCTGACNNNNATTCTNGGNCNCGACCTCTCCANATACCANCNNATGANNGNGAANGANNTNATNNTGAANCNNATNGTNACNNGNNTGANCANNNXXXXXXANNTNCANNXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXNXXXXXXXXXXXXXXXXXXNCNNNNNNNNNNNXXXXXXXXXXXXXXNNNXXXXXXXXXXXXNCNANNNNNNNNNTGANAANCGNAANGAGCTCATNATATCANCAAAACAATTCAAAGATGGATACNCCTATNNNNNANCGNNGANNNNNNNNCGNNCXXXNAGNTANNTGGANCANTTNTGGNTNTGNGGATCGNGGTNXXXXXXX
[[ 11  66]
 [744 796]] [55 52]
# Candidate amplicon search - within conserved sequences and between consecutive conserved sequences
def get_candidate_amplicons(cons, min_len=190, max_insert=50):
    '''
    Given conservation intervals, minimum amplicon lenght and maximum insert length,
    return np.array of plausible amplicons with insert positions'''
    ampls = []
    for reg in cons: # internal amplicons
        if reg[1] - reg[0] >= min_len:
            ampls.append((reg[0], reg[1], 0, 0))
    for i in range(len(cons) - 1):
        for j in range(i + 1, len(cons)):
            if cons[j, 0] - cons[i, 1] <= max_insert:
                if cons[j, 1] - cons[i, 0] >= min_len:
                    ampls.append((cons[i, 0], cons[j, 1],
                                  cons[i, 1], cons[j, 0]))
    return ampls

# function test - long run
# for alignment in AlignIO.parse("../../data/AgamP3_maf/chr2L.maf", "maf"):
#     if len(alignment) >= min_species and alignment.get_alignment_length() >= min_aligned:
#         seq = seq_repr(alignment)
#         cons = get_conserved_subsequences(seq, max_ns=max_ns, max_xs=max_xs, min_len=min_conserved)
#         if cons is not None:
#             ampls = get_candidate_amplicons(cons, min_aligned, max_insert)
#             if len(ampls) > 0:
#                 for reg in cons:
#                     print(reg, seq[reg[0]:reg[1]])
#                 for ampl in ampls:
#                     print(alignment[:, ampl[0]:ampl[1]])
#                 print(ampls)
#                 break[110 227] TCNTTCATGTACCANGAACGCGCCATGACCGAGGGNTGNGCCTCNCCACCACCNGCNGCGGTACTGAGACTTCACAATCAATCNCCATACTACAATATNGTGCGTTTNNXTTNCTTN
[1613 1926] AGNNGNACCGANTCGTCCAANCAGCTGGACGCGAAGATGAAGCACAGTAAGGANCTGGACNNGXXXGNNGCNGGNGGXXXCCCNGGNGACCACGGCTATAACCCGAACCACTATATGCGTTCNATTCCAGGTCTNATNTATCACGGCACGCAATCGAGCACNTCNTCCGATTTNTCGCCGATGTCCGAACAAAAGTCNTTACCNCGGCGTGGCCGTTCAAGGTACCATCATCTTCANCTTCATANCACTAACACCACACCANGNCACAAGNCCTCCAAAGCTCAGTCACCANTAGCGTCNCCCCGTAGTAGNN
[1941 2018] XXNACNAXXXNAACGTNCCGATACAGCTTCCCCGCATGCCGTCCCAGTTTCGNCCNATNCACAGTAGTNGAACNATN
SingleLetterAlphabet() alignment with 21 rows and 313 columns
AGCAGAACCGAATCGTCCAATCAGCTGGACGCGAAGATGAAGCA...GTT AgamP3.chr2L
AGCAGAACCGAATCGTCCAATCAGCTGGACGCGAAGATGAAGCA...GTT AgamS1.chrscf_1106392397111
AGCAGAACCGAATCGTCCAATCAGCTGGACGCGAAGATGAAGCA...GTT AgamM1.chrscf_1925491356
AGCAGAACCGAATCGTCCAATCAGCTGGACGCGAAGATGAAGCA...GTT AmerM1.chrsupercont1.338
AGCAGAACCGAATCGTCCAATCAGCTGGACGCGAAGATGAAGCA...GTT AaraD1.chrKB704529
AGCAGAACCGAATCGTCCAATCAGCTGGACGCGAAGATGAAGCA...GTT AquaS1.chrKB665943
AGCAGAACCGAATCGTCCAATCAGCTGGACGCGAAGATGAAGCA...GTT AmelC1.chrsupercont1.4721
AGCAGAACCGAATCGTCCAATCAGCTGGACGCGAAGATGAAGCA...GTA AchrA1.chrKB700038
AGCCGAACCGAATCGTCCAATCAGCTGGACGCGAAGATGAAGCA...GTT AepiE1.chrKB671571
AGCAGAACCGAATCGTCCAACCAGCTGGACGCGAAGATGAAGCA...GTT AminM1.chrKB663721
AGCAGAACCGAATCGTCCAACCAGCTGGACGCGAAGATGAAGCA...GTT AculA1.chrsupercont1.1319
AGCAGAACCGAATCGTCCAACCAGCTGGACGCGAAGATGAAGCA...GTT AfunF1.chrKB668790
AGCCGAACCGAATCGTCCAACCAGCTGGACGCGAAGATGAAGCA...GTT AsteS1.chrKB665154
AGCCGAACCGAATCGTCCAACCAGCTGGACGCGAAGATGAAGCA...GTT AsteI2.chrscaffold_00146
AGCCGAACCGAATCGTCCAATCAGCTGGACGCGAAGATGAAGCA...GTT AmacM1.chrsupercont1.55
AGCCGTACCGAGTCGTCCAACCAGCTGGACGCGAAGATGAAGCA...GTT AfarF1.chrsupercont1.172
AGCCGAACCGAGTCGTCCAACCAGCTGGACGCGAAGATGAAGCA...GTT AdirW1.chrKB672835
AGCCGCACCGAGTCGTCCAACCAGCTGGACGCGAAGATGAAGCA...GCT AsinS1.chrsupercont1.628
...
AGTCGCACCGAATCGTCCAACCAGCTGGACGCGAAGATGAAGCA...GTT AalbS1.chrKB672342
SingleLetterAlphabet() alignment with 21 rows and 405 columns
AGCAGAACCGAATCGTCCAATCAGCTGGACGCGAAGATGAAGCA...ATC AgamP3.chr2L
AGCAGAACCGAATCGTCCAATCAGCTGGACGCGAAGATGAAGCA...ATC AgamS1.chrscf_1106392397111
AGCAGAACCGAATCGTCCAATCAGCTGGACGCGAAGATGAAGCA...ATC AgamM1.chrscf_1925491356
AGCAGAACCGAATCGTCCAATCAGCTGGACGCGAAGATGAAGCA...ATC AmerM1.chrsupercont1.338
AGCAGAACCGAATCGTCCAATCAGCTGGACGCGAAGATGAAGCA...ATC AaraD1.chrKB704529
AGCAGAACCGAATCGTCCAATCAGCTGGACGCGAAGATGAAGCA...ATC AquaS1.chrKB665943
AGCAGAACCGAATCGTCCAATCAGCTGGACGCGAAGATGAAGCA...ATC AmelC1.chrsupercont1.4721
AGCAGAACCGAATCGTCCAATCAGCTGGACGCGAAGATGAAGCA...ATC AchrA1.chrKB700038
AGCCGAACCGAATCGTCCAATCAGCTGGACGCGAAGATGAAGCA...ATC AepiE1.chrKB671571
AGCAGAACCGAATCGTCCAACCAGCTGGACGCGAAGATGAAGCA...ATC AminM1.chrKB663721
AGCAGAACCGAATCGTCCAACCAGCTGGACGCGAAGATGAAGCA...ATC AculA1.chrsupercont1.1319
AGCAGAACCGAATCGTCCAACCAGCTGGACGCGAAGATGAAGCA...ATC AfunF1.chrKB668790
AGCCGAACCGAATCGTCCAACCAGCTGGACGCGAAGATGAAGCA...ATC AsteS1.chrKB665154
AGCCGAACCGAATCGTCCAACCAGCTGGACGCGAAGATGAAGCA...ATC AsteI2.chrscaffold_00146
AGCCGAACCGAATCGTCCAATCAGCTGGACGCGAAGATGAAGCA...ATC AmacM1.chrsupercont1.55
AGCCGTACCGAGTCGTCCAACCAGCTGGACGCGAAGATGAAGCA...ATC AfarF1.chrsupercont1.172
AGCCGAACCGAGTCGTCCAACCAGCTGGACGCGAAGATGAAGCA...ATC AdirW1.chrKB672835
AGCCGCACCGAGTCGTCCAACCAGCTGGACGCGAAGATGAAGCA...ATC AsinS1.chrsupercont1.628
...
AGTCGCACCGAATCGTCCAACCAGCTGGACGCGAAGATGAAGCA...ATA AalbS1.chrKB672342
[(1613, 1926, 0, 0), (1613, 2018, 1926, 1941)]
def gapped_coord(aln, coord, ref=0):
    '''
    Transforms coordinate in maf alignment according to number of gaps in ref (i-th seq in alignment)
    '''
    ngaps = str(aln[ref, :coord].seq).count('-')
    return aln[ref].annotations['start'] + coord - ngaps

def alignment_to_amplicons(alignment, min_species, min_aligned, max_xs, max_ns, min_conserved, max_insert, annotated=True):
    '''
    Given alignment and filtering paramters
    return list of (alignment, target start, target end)
    '''
    ampl_data = []
    if len(alignment) >= min_species and alignment.get_alignment_length() >= min_aligned:
        seq = seq_repr(alignment)
        cons = get_conserved_subsequences(seq, max_ns=max_ns, max_xs=max_xs, min_len=min_conserved)
        if cons is not None:
            ampls = get_candidate_amplicons(cons, min_aligned, max_insert)
            if len(ampls) > 0:
                for ampl in ampls:
                    ampl_aln = alignment[:, ampl[0]:ampl[1]]
                    if annotated:
                        ampl_aln[0].annotations = alignment[0].annotations.copy()
                        ampl_aln[0].annotations['start'] = gapped_coord(alignment, ampl[0])
                        ampl_aln[0].annotations['size'] = gapped_coord(alignment, ampl[1]) - ampl_aln[0].annotations['start']
                    ampl_data.append((ampl_aln, (ampl[2] - ampl[0], ampl[3] - ampl[0])))
                return ampl_data
    return None

# function test - long run
# amplicons = []
# for alignment in AlignIO.parse("../../data/AgamP3_maf/chr2L.maf", "maf"):
#     a = alignment_to_amplicons(alignment, min_species, min_aligned, max_xs, max_ns, min_conserved, max_insert)
#     if a is not None:
#         amplicons.extend(a)
# #         print(amplicons)
# #         break

# print(len(amplicons))26
# exctract amplicons from all chromosomes
chromosomes = ['2L','2R','3L','3R','X']
chrom_files = ["../../data/AgamP3_maf/chr" + chrom + ".maf" for chrom in chromosomes]

amplicons = []

# this actually takes some time
for chrom_file in chrom_files:
    for alignment in AlignIO.parse(chrom_file, "maf"):
        a = alignment_to_amplicons(alignment, min_species, min_aligned, max_xs, max_ns, min_conserved, max_insert)
        if a is not None:
            amplicons.extend(a)
print(len(amplicons))126
%pwd_____no_output_____# write amplicons
count = 0
with open("../20180129_phylo_ampliseq/20180226_amplicons.maf", "w") as handle:
    for a in amplicons:
        count += AlignIO.write(a[0], handle, "maf")
count_____no_output_____# write targets
with open("../20180129_phylo_ampliseq/20180226_targets.txt", 'w') as handle:
    for a in amplicons:
        handle.write('\t'.join([str(c) for c in a[1]]) + '\n')_____no_output_____!grep AgamP3.chr 20180226_amplicons.maf | cut -d ' ' -f2 | sort | uniq -c
   26 AgamP3.chr2L
  49 AgamP3.chr2R
  17 AgamP3.chr3L
  33 AgamP3.chr3R
   1 AgamP3.chrX

# TODO

- target search: clusters of N/Xs + 20180226_targets.txt
- target search: use DistanceCalculator on concatenated targets to select minimum set of phylogenetically informative markers
- apart from prospective amplicons and targets, produce reports and trees per amplicon_____no_output_____# Other amplicon-related developments

- search amplicons and targets in mtDNA data
- same for 16S, but also consider species ID PCR
- limited taxonomic primer pick from maf's (e.g., species marker for gambiae complex)
- incorporation of population data - variable sites evaluated by frequency/geographic associations
- Chris Kozak CRISPR target design script should be similar to population examination (look in Ag1000g notebooks)
_____no_output_____

    _____no_output_____


# Notebook from stewarthe6/AMPL-1
Path: atomsci/ddm/examples/tutorials/AMPL_FNL_Wrshp2_1.ipynb

_____no_output_____

from IPython.display import Image
Image(url='https://github.com/ATOMScience-org/AMPL/blob/master/atomsci/ddm/examples/tutorials/Img/ml-ready.png?raw=true')_____no_output_____

# AMPL Workshop2-1: Exploratory data analysis to create partially curated datasets
_____no_output_____## Goal

The goal of the workshop is to take single target binding assay
data collected from three different chemoinformatics data sources
(ChEMBL, DTC and ExCAPE-DB) and use AMPL to create a single harmonized
Machine-Learning ready data. For demonstation, we will use HRH1 protein target binding data.

We use the following three sequential notebooks to accomplish the tasks:

1.   https://github.com/ATOMScience-org/AMPL/blob/master/atomsci/ddm/examples/tutorials/AMPL_FNL_Wrshp2_1.ipynb
2.   https://github.com/ATOMScience-org/AMPL/blob/master/atomsci/ddm/examples/tutorials/AMPL_FNL_Wrshp2_2.ipynb
3.   https://github.com/ATOMScience-org/AMPL/blob/master/atomsci/ddm/examples/tutorials/AMPL_FNL_Wrshp2_3.ipynb

**raw_datasets (input) --> AMPL_FNL_Wrshp2_1.ipynb --> AMPL_FNL_Wrshp2_2.ipynb --> AMPL_FNL_Wrshp2_3.ipynb --> ML-ready data**

Links for the chemoinformatics datbases:
* ChEMBL: https://www.ebi.ac.uk/chembl/
* DTC: https://drugtargetcommons.fimm.fi/
* ExCAPE-DB: https://solr.ideaconsult.net/search/excape/
* NCBI Gene information: https://www.ncbi.nlm.nih.gov/gene?Db=gene&Cmd=DetailsSearch&Term=3269

_____no_output_____**In this notebook, we will not be covering the details of the protein receptor biology (visualizing 3D structures of receptors, small molecules etc) and why HRH1 is chosen as a target.If you are interested, please check out our previous workshop links:
* https://github.com/ATOMScience-org/AMPL/blob/master/atomsci/ddm/examples/tutorials/AMPL_FNL_Workshop_06052021.ipynb
* https://github.com/ravichas/AMPL-workshop-1 _____no_output_____## Here is an overview of the steps we will follow in this notebook_____no_output_____

# from IPython.display import Image
Image(url='https://github.com/ATOMScience-org/AMPL/blob/master/atomsci/ddm/examples/tutorials/Img/GCP-AMPL-FNL_Wrshp2-1-overview.png?raw=true')_____no_output_____

# Install AMPL software  _____no_output_____

! pip install rdkit-pypi
! pip install --pre deepchem

import deepchem
# print(deepchem.__version__)
! pip install umap
! pip install llvmlite==0.34.0  --ignore-installed
! pip install umap-learn
! pip install molvs
! pip install bravado_____no_output_____import deepchem as dc

# get the Install AMPL_GPU_test.sh
!wget 'https://raw.githubusercontent.com/ATOMScience-org/AMPL/master/atomsci/ddm/examples/tutorials/config/install_AMPL_GPU_test.sh'

# run the script to install AMPL
! chmod u+x install_AMPL_GPU_test.sh
! ./install_AMPL_GPU_test.sh_____no_output_____

# Load packages_____no_output_____

%matplotlib inline
# manipulate data
import pandas as pd

# plot data
import numpy as np
import matplotlib.pyplot as plt

# curate data
from atomsci.ddm.utils import struct_utils
from atomsci.ddm.utils import curate_data
from atomsci.ddm.pipeline import dist_metrics

# visualize compound structures
import tempfile
from rdkit import Chem
from rdkit.Chem import Draw
from itertools import islice
from IPython.display import Image, display

# visualize data
import seaborn as sns
import matplotlib_venn as mpv
from scipy.stats import pearsonr

# set pandas options
pd.set_option('display.max_columns',(90))
pd.set_option('display.max_rows',(20))_____no_output_____# set up visualization parameters
sns.set_context("paper")
sns.set_style("whitegrid")
plt.rcParams['figure.figsize'] = [10,10]

colors = [
    "#6EC8BE",
    "#BE2369",
    "#FFC30F",
    "#694691",
    "#EB1E23",
    "#7682A4",
    "#A7DDD8",
    "#373C50",
]
# Set your custom color palette
pal=sns.color_palette(colors)
sns.set_palette(pal)
sns.palplot(pal)_____no_output_____

# Input files needed for this notebook

The following files will be downloaded from a GitHub repository.

> __`hrh1_chembl.csv`__

> __`hrh1_dtc.csv`__

> __`hrh1_excape.csv`__

> __`1591412781568494159.txt`__

> __`904065732039684223.txt`__
_____no_output_____# Questions for the data exploration phase of the project_____no_output_____Here is a list of possible questions during exploration:
- Number of data points in each DB?
- Molecular identifier types from each DB?
  - For example, #HBD is it an integer or a string variable?
- Outcome variable (types, units) from each DB?
- Modeling works well in log-transformed data, pIC50 (IC50 -> pIC50)?
  - pIC50 = -log(IC50)
- What molecular (and other) identifiers exist for compounds from each database?
- What assay response types are there in each file?
- How we might combine these data sources together?_____no_output_____# Load ChEMBL data_____no_output_____

! wget https://raw.githubusercontent.com/ATOMScience-org/AMPL/master/atomsci/ddm/examples/tutorials/datasets/hrh1_chembl.csv >& /dev/null
chembl = pd.read_csv("hrh1_chembl.csv", sep=';')_____no_output_____

## Examine data
> __What molecular (and other) identifiers exist for compounds from each database?__

> __What assay response types are there in each file?__

> __How we might combine these data sources together?__
_____no_output_____

chembl.columns_____no_output_____chembl.columns = chembl.columns.str.replace(' ','_') # get rid of annoying spaces in column names
print(chembl.shape)(5341, 45)

**You can add other cleaning or tidying steps here**_____no_output_____

chembl.head(3)_____no_output_____

## **Chembl Standard Units:**

According to Chembl, *The published units are taken directly from the literature and we then attempt to standardise these to report as a **standard type**. This is an ongoing curation task, which was started with the most common units first.*_____no_output_____

pd.DataFrame(chembl.Standard_Type.value_counts()).T_____no_output_____

## Curation Step: Subset data for the standard types you want to keep
> __ML algorithms need lots of data, in general keep the most abundant types__

> __IC50, Log IC50, pIC50 may be combined with proper care__
_____no_output_____

print(chembl.shape)
chembl = chembl[chembl.Standard_Type.isin(['Ki', 'IC50', 'EC50'])]
chembl.shape(5341, 45)

### Examine assay types_____no_output_____

assays = pd.DataFrame(chembl[chembl.Standard_Type=='Ki'].Assay_Description.value_counts()).reset_index()
assays.columns=['Assay_Description', 'count']
assays.to_csv('HRH1_ChEMBL_Assays_Ki.csv')
print('Ki assays:')
display(assays)Ki assays:
assays = pd.DataFrame(chembl[chembl.Standard_Type.isin(['IC50', 'EC50'])].Assay_Description.value_counts()).reset_index()
assays.columns=['Assay_Description', 'count']
assays.to_csv('HRH1_ChEMBL_Assays_XC50.csv')
print('XC50 assays:')
display(assays)XC50 assays:

## Exercise: Explore datasets
> load dtc and excape datasets

> explore the loaded (dtc and excape) dataframes to answer the following questions

## Possible list of questions:
> How many assay values in each dataset?

> What are the molecular identifiers from each dataset?

> What are the data types from each dataset?

> What are the data units available from each dataset?

> What is the formula to translate IC50 to pIC50? (Hint: Check the following wikipedia link, https://en.wikipedia.org/wiki/IC50)

> What kinds of assays are represented in the datasets?
_____no_output_____---
# Load DTC data_____no_output_____

! wget https://raw.githubusercontent.com/ATOMScience-org/AMPL/master/atomsci/ddm/examples/tutorials/datasets/hrh1_dtc.csv >& /dev/null
dtc = pd.read_csv("hrh1_dtc.csv")_____no_output_____

    DTC Exercise-1: EDA of DTC dataset :
    <it>

 Replace column name empty spaces with "_"

 Print the dimensions of the dataframe

 Filter the dataset to retain only standard types, KI, Ki, IC50, EC50

 How many unique values of standard types are available?

_____no_output_____

     Solution for DTC Exercise-1: Try on your own. If you want to see the solution, click the following cell

_____no_output_____Click here for the solution

```python
dtc.columns = dtc.columns.str.replace(' ','_')
print("dtc.shape: ", dtc.shape)
temp = pd.DataFrame(dtc['standard_type'].value_counts()).T
print(temp)

dtc = dtc[dtc.standard_type.isin(['KI', 'Ki', 'IC50', 'EC50'])]

# change KI to Ki
dtc.standard_type = np.where(dtc.standard_type == 'KI', 'Ki', dtc.standard_type)
dtc.standard_type.unique()
```

_____no_output_____

#***********************************************************
# solution cell code chunk copied here to run the notebook *
#***********************************************************

dtc.columns = dtc.columns.str.replace(' ','_')
print("dtc.shape: ", dtc.shape)
temp = pd.DataFrame(dtc['standard_type'].value_counts()).T
print(temp)

dtc = dtc[dtc.standard_type.isin(['KI', 'Ki', 'IC50', 'EC50'])]

# change KI to Ki
dtc.standard_type = np.where(dtc.standard_type == 'KI', 'Ki', dtc.standard_type)
dtc.standard_type.unique()dtc.shape:  (4819, 33)
                 KI  IC50  INHIBITION  PKB   Ki  ACTIVITY  EC50  PEC50  ALPHA  \
standard_type  2491  1230         354  150  118        87    49     47     41

               KB  INTRINSIC ACTIVITY  Inhibition  Intrinsic activity  KD  \
standard_type  39                  38          35                  23  23

               EFFECT  CHANGE  LOG IC50  PKI  EMAX  Activity  EFFICACY  PIC50  \
standard_type      20      19        18   13     5         4         4      3

               RATIO  Kb  PKP  SELECTIVITY RATIO  P[A50]  LOG EC50
standard_type      2   2    1                  1       1         1

---
# Load ExCAPE-DB data_____no_output_____

! wget https://raw.githubusercontent.com/ATOMScience-org/AMPL/master/atomsci/ddm/examples/tutorials/datasets/hrh1_excape.csv >& /dev/null
excape = pd.read_csv("hrh1_excape.csv")
_____no_output_____

    Excape Exercise-1: EDA of ExCAPE-DB dataset:
    <it>

 Replace column name empty spaces with "_"

 Print the dimensions of the dataframe

 Explore assay information

_____no_output_____

     Solution for Excape Exercise-1: Try on your own. If you want to see the solution, click the following cell

_____no_output_____Click here for the solution

```python
# replace excape column names with empty space with underscore "_"
excape.columns = excape.columns.str.replace(' ','_')

# print the dimensions of excape dataframe
print(excape.shape)

excape.Activity_Flag.unique()

#  log10 of concentration value in MOLAR units
#  np.log10(1.81e-9)

#other useful info:
#- standard relation column
#- assay information

# important: need to verify that all the assays are measuring the same thing
len(chembl.Assay_Description.unique())
```

_____no_output_____

#***********************************************************
# solution cell code chunk copied here to run the notebook *
#***********************************************************

# replace excape column names with empty space with underscore "_"
excape.columns = excape.columns.str.replace(' ','_')

# print the dimensions of excape dataframe
print(excape.shape)

excape.Activity_Flag.unique()

#  log10 of concentration value in MOLAR units
#  np.log10(1.81e-9)

# other useful info:
# - standard relation column
# - assay information

# important: need to verify that all the assays are measuring the same thing
len(chembl.Assay_Description.unique()) (1283, 11)

# EDA: Assay data responses
> __What type of variable are the data responses?__

> __What kind of ML model would you build to predict this data?__

> __What kind of visualizations & analysis can you use to understand more about the data?__
_____no_output_____

chembl.tail(3)_____no_output_____chembl.Standard_Units.unique()_____no_output_____chembl.Standard_Relation.unique()_____no_output_____

## **Curation step**: Change `Standard Units` to be the same for all responses.
> __This task may not be necessary for HRH1, but might be essential for other datasets__

> __create the column anyway for use later__
_____no_output_____

chembl['Standard_Units'].value_counts()_____no_output_____# change uM to nM units so they're all the same
chembl.loc[:, 'Standard_Value_nM'] = np.where(chembl.Standard_Units == 'uM',    # where units are uM,
                                              chembl.Standard_Value * 1000, # multiply Standard_Value by 1000,
                                              chembl.Standard_Value)        # otherwise take the Standard_Value_____no_output_____

## EDA: Summarize, describe, plot data for analysis_____no_output_____

# summary statistics
chembl.describe()_____no_output_____chembl.head(3)_____no_output_____

**Why do some columns seem numeric (ex., Molecular Weight, AlogP etc)  but not listed in the `describe()` command? Examine chembl csv file. The reason for this behavior is due to some cells for these columns contain `None` entries that make it an `object` datatype rather than `float64`**_____no_output_____

chembl=chembl.replace('None',np.nan)_____no_output_____# after removing None you have to recast the column as numeric
numeric_cols=['Molecule_Max_Phase', 'Molecular_Weight',
              '#RO5_Violations', 'AlogP',
              'Standard_Value_nM', 'pChEMBL_Value']
for col in numeric_cols:
    chembl[col]=chembl[col].astype(float)_____no_output_____chembl.head(5)_____no_output_____chembl[numeric_cols].hist(figsize=(10,10));_____no_output_____

> __Note that pChembl value is better normalized than standard value__

> __Recall that there are lots of different activity types / assays represented in the value columns. Let's split those up:__
_____no_output_____

# examine STANDARD values and pChembl values PER standard type
chembl_types=chembl.pivot_table(index = 'Molecule_ChEMBL_ID', columns = 'Standard_Type', values='Standard_Value_nM', aggfunc='mean')
display(chembl_types.describe())
chembl_types.hist(figsize=(13,13), bins = 20);_____no_output_____

- **What do you notice about the standard values?**_____no_output_____

chembl_types=chembl.pivot_table(index = 'Molecule_ChEMBL_ID',
                                columns = 'Standard_Type',
                                values='pChEMBL_Value',
                                aggfunc='mean')
display(chembl_types.describe())
chembl_types.hist(figsize=(6,6));_____no_output_____

- **What do you notice about the pChEMBL values?**_____no_output_____

    DTC-Exercise 2: Explore DTC dataset :

_____no_output_____

     Solution for DTC Exercise-2: Try on your own. If you want to see the solution, click the following cell

_____no_output_____Click here for the solution

```python
dtc=dtc.replace('None', np.nan)
dtc.head()

dtc.standard_units.unique() #already all nM

dtc.standard_type.unique()

dtc[dtc.standard_units=='NM'].standard_type.unique()

## **Curation step:** create pValues from normal values

# add pX column
dtc['pDTC_Value'] = np.where(dtc.standard_units == 'NM',
                             -np.log10(dtc.standard_value/1000000000 ),
                             dtc.standard_value)

dtc.describe()

numeric_cols=['standard_value', 'pDTC_Value']
dtc[numeric_cols].hist(bins=20, figsize=(10,5));

dtc_types=dtc.pivot_table(index = 'compound_id', columns = 'standard_type', values='standard_value', aggfunc='mean')
display(dtc_types.describe())
dtc_types.hist(figsize=(13,13));

dtc_types=dtc.pivot_table(index = 'compound_id', columns = 'standard_type', values='pDTC_Value', aggfunc='mean')
display(dtc_types.describe())
dtc_types.hist(figsize=(10,10));
```

_____no_output_____

#***********************************************************
# solution cell code chunk copied here to run the notebook *
#***********************************************************

dtc=dtc.replace('None', np.nan)
dtc.head()

dtc.standard_units.unique() #already all nM

dtc.standard_type.unique()

dtc[dtc.standard_units=='NM'].standard_type.unique()

## **Curation step:** create pValues from normal values

# add pX column
dtc['pDTC_Value'] = np.where(dtc.standard_units == 'NM',
                             -np.log10(dtc.standard_value/1000000000 ),
                             dtc.standard_value)

dtc.describe()

numeric_cols=['standard_value', 'pDTC_Value']
dtc[numeric_cols].hist(bins=20, figsize=(10,5));

dtc_types=dtc.pivot_table(index = 'compound_id', columns = 'standard_type', values='standard_value', aggfunc='mean')
display(dtc_types.describe())
dtc_types.hist(figsize=(13,13));

dtc_types=dtc.pivot_table(index = 'compound_id', columns = 'standard_type', values='pDTC_Value', aggfunc='mean')
display(dtc_types.describe())
dtc_types.hist(figsize=(10,10));_____no_output_____

    Excape Exercise 2: Explore ExCAPE-DB dataset :

_____no_output_____

     Solution for ExCAPE Exercise-2: Try on your own. If you want to see the solution, click the following cell

_____no_output_____Click here for the solution

```python
excape=excape.replace('None', np.nan)
excape.head()

# excape only has one column we care about
display(excape.describe())
excape.pXC50.hist(figsize=(5,5));
```

_____no_output_____

#***********************************************************
# solution cell code chunk copied here to run the notebook *
#***********************************************************

excape=excape.replace('None', np.nan)
excape.head()

# excape only has one column we care about
display(excape.describe())
excape.pXC50.hist(figsize=(5,5));_____no_output_____

# **What are the relevant input and the outputs for modeling?**

**ChEMBL**
*   Input: SMILES
*   Output: IC50 or other units

**ExCAPE-DB**
* Input: SMILES
* Output: PXC50 or Activity_Flag

**DTC**
* Input: ChEMBL ID or InChi key
* Output pDTC

_____no_output_____# Exercise: compare pResponse values across all three datasets
- which responses can you compare across all three datasets?
- create a histogram or kde plot with legend showing distributions for all three datasets on the same plot
- (try later) use numpy's `arange()` function with the `bins` argument in the `distplot` function to create equal sized bins for every dataset (find information on how to specify bins here: https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.hist.html)_____no_output_____

chembl.head(3)_____no_output_____chembl.Standard_Type.unique()_____no_output_____dtc.standard_type.unique()_____no_output_____excape.shape_____no_output_____

---
# Histogram plot

https://seaborn.pydata.org/generated/seaborn.histplot.html_____no_output_____

dtc.standard_type.value_counts()_____no_output_____chembl.Standard_Type.isin(['IC50','EC50'])_____no_output_____fig, ax = plt.subplots(1, sharex=True, figsize=(10,10))
sns.histplot(data=chembl[chembl.Standard_Type.isin(['IC50', 'EC50'])], x='pChEMBL_Value', ax=ax, color=pal[0])
sns.histplot(dtc[dtc.standard_type.isin(['IC50', 'EC50'])].pDTC_Value, ax=ax, color=pal[1])
sns.histplot(excape.pXC50, ax=ax, color=pal[2], alpha = 0.2)
ax.legend(labels=['chembl', 'dtc', 'excape']);_____no_output_____

---
# KDE Plot

"A kernel density estimate (KDE) plot is a method for visualizing the distribution of observations in a dataset, analagous to a histogram. KDE represents the data using a continuous probability density curve in one or more dimensions." taken from https://seaborn.pydata.org/generated/seaborn.kdeplot.html_____no_output_____

fig, ax = plt.subplots(1, sharex=True, figsize=(10,10))
sns.kdeplot(data=chembl[chembl.Standard_Type.isin(['IC50', 'EC50'])], x='pChEMBL_Value', ax=ax, color=pal[0])
sns.kdeplot(dtc[dtc.standard_type.isin(['IC50', 'EC50'])].pDTC_Value, ax=ax, color=pal[1])
sns.kdeplot(excape.pXC50, ax=ax, color=pal[2])
ax.legend(labels=['chembl', 'dtc', 'excape']);_____no_output_____

# Analysis
- What value types you would model and why?
- How would you use this data for a classification model?_____no_output_____- For this dataset we could model either pXC50 or pKI values. They are the most abundant in the dataset and commonly used for modeling. pKI is more normally distributed, but pXC50 values allow inclusion of excape data.

According to some sources, these two datapoints can be combined in various ways, as well, but that's beyond the scope of this class.

- For this dataset, one could choose a reasonable IC50 concentration to use as a threshold (perhaps 10uM, or consult an experimental scientist), and anything with an IC50 `above` that threshold is `inactive` and IC50s `below` this threshold is `active`._____no_output_____# DTC: Fill in empty SMILES string using InChi Keys_____no_output_____

dtc.head(3)_____no_output_____

Let us start with `compound_id` column and try to convert them to SMILES string using PubChem ID Exchange service_____no_output_____# **Curation step** & exercise: Get SMILES for DTC data from chemical identifiers_____no_output_____

dtc['compound_id'].head(5)_____no_output_____dtc['standard_inchi_key'].isna().sum()_____no_output_____dtc['compound_id'].isna().sum()_____no_output_____

Since AMPL uses SMILES strings as input, we will use them as our primary data curation tool.
1. open DTC file in excel or google sheets
2. copy/paste the compound ID (ChEMBLXXXXXXX) column into pubchem ID exchange service: https://pubchem.ncbi.nlm.nih.gov/idexchange/idexchange.cgi
    * Did you get the whole column??
    * Be sure to select the correct `registry ID` for the input id list (see below for a screenshot of PubChem)
    * Select `Operator_type` as `Same CID` and `Ouput IDs` as "SMILES"
3. upload the resulting text file from `PubChem Identifier Exchange Service` into jupyter_____no_output_____

from IPython.display import Image
Image("https://raw.githubusercontent.com/ATOMScience-org/AMPL/master/atomsci/ddm/examples/tutorials/Img/PubChemCIDExchange.png",
      width = 900, height = 900)_____no_output_____# open file from pubchem ID exchange service
!wget https://raw.githubusercontent.com/ATOMScience-org/AMPL/master/atomsci/ddm/examples/tutorials/datasets/1591412781568494159.txt >& /dev/null
dtc_smiles = pd.read_csv("1591412781568494159.txt", sep="\t", header=None)
dtc_smiles=dtc_smiles.rename(columns = {0:'ChEMBL_ID',1:'SMILES'})
dtc_smiles.head()_____no_output_____# map chembl id to smiles using a dict
dtc['SMILES'] = dtc['compound_id'].map(dict(zip(dtc_smiles.ChEMBL_ID, dtc_smiles.SMILES)))_____no_output_____# what's missing?
print("Number of compounds in dtc: ", dtc_smiles.shape[0])
print("DTC compounds that dont have Chembl IDs:", len(dtc[dtc['compound_id'].isna()]))
print("DTC compounds after convertion have No SMILES string:", len(dtc[dtc.SMILES.isna()]))Number of compounds in dtc:  4774
DTC compounds that dont have Chembl IDs: 44
DTC compounds after convertion have No SMILES string: 110
dtc[dtc.SMILES.isna()].head(3)_____no_output_____

# Try to recover the missing smiles from other chemical identifiers in the DTC file._____no_output_____

# select inchikeys from the 110 missing smiles rows
dtc[dtc.SMILES.isna()]['standard_inchi_key'].unique().tolist()_____no_output_____

#### Copy the following `standard_inchi_key` ids into PubChem exchange service and convert it to SMILES
```
ABZSPJVXTTUFAA-UHFFFAOYSA-N
FERVXSHGEVPGHF-UHFFFAOYSA-N
FTCWKSGDHXCEMZ-UHFFFAOYSA-N
HXTGXYRHXAGCFP-UHFFFAOYSA-N
IHIXIJGXTJIKRB-UHFFFAOYSA-N
KIWQWJKWBHZMDT-GSVOUGTGSA-N
PDNJLMZEGXHSCU-GSVOUGTGSA-N
QUROTGLADLKIIK-UHFFFAOYSA-N
SUGVYNSRNKFXQM-ACSDJOOWSA-N
TXZPMHLMPKIUGK-UHFFFAOYSA-N
VBOQYPQEPHKASR-GSVOUGTGSA-N
VGFZCFWVSYIXEK-UHFFFAOYSA-N
VQOXZBDYSJBXMA-VHFLTRTASA-N
ZQAHOENZMFACFJ-UHFFFAOYSA-N
```_____no_output_____

! wget https://raw.githubusercontent.com/ATOMScience-org/AMPL/master/atomsci/ddm/examples/tutorials/datasets/904065732039684223.txt >& /dev/null
inchi_smiles = pd.read_csv("904065732039684223.txt", sep='\t', header=None)
inchi_smiles=inchi_smiles.rename(columns = {0:'INCHIKEY',1:'SMILES'})
inchi_smiles.head(3)_____no_output_____dtc.head(3)_____no_output_____# map inchikey to smiles using a dict - map ONLY where there are NA values, don't overwrite existing smiles!
dtc.loc[dtc.SMILES.isna(), 'SMILES'] = dtc.loc[dtc.SMILES.isna(), 'standard_inchi_key'].map(dict(zip(inchi_smiles.INCHIKEY, inchi_smiles.SMILES)))

# what's missing?
print("No InchiKey in DTC:", len(dtc[dtc['standard_inchi_key'].isna()]))
print("No SMILES from InchiKey or ChemblID in DTC:", len(dtc[dtc.SMILES.isna()]))No InchiKey in DTC: 152
No SMILES from InchiKey or ChemblID in DTC: 66

Pubchem doesn't ID some of these compounds. Depending on how precious your data is and how many data points are missing, it may be worth going to other sources manually, such as chemspider: http://www.chemspider.com/Search.aspx?q=InChIKey=BXTUHNWXQLWICJ-DIXMSKSGSA-L_____no_output_____

dtc[dtc.SMILES.isna()].head(3)_____no_output_____

# Save partially curated files_____no_output_____

chembl.to_csv('HRH1_ChEMBL_sel.csv')_____no_output_____## If you have completed curating DTC and ExCAPE-DB, you can save them with the following command:_____no_output_____dtc.to_csv('HRH1_DTC_sel.csv')
excape.to_csv('HRH1_Excape_sel.csv')_____no_output_____!dateSat Sep 18 12:48:39 UTC 2021


# Notebook from BeeQC/ANODE-reproducibility
Path: augmented-neural-ode-example.ipynb

import matplotlib.pyplot as plt
%matplotlib inline
import torch

device = torch.device('cpu')_____no_output_____

# Augmented Neural ODEs
This notebook contains example of how to train Neural ODEs and Augmented Neural ODEs and to visualize their differences. This includes differences in how they warp the input space, how they generalize and how their ODEs map inputs to features. _____no_output_____## Create and visualize training data_____no_output_____

from experiments.dataloaders import ConcentricSphere
from torch.utils.data import DataLoader
from viz.plots import single_feature_plt

# Create training data in 2D, consisting of a concentric disk and an annulus
data_dim = 2
data_concentric = ConcentricSphere(data_dim, inner_range=(0., 1), outer_range=(1, 1.5),
                                   num_points_inner=2000, num_points_outer=2000)
dataloader = DataLoader(data_concentric, batch_size=64, shuffle=True)

# Visualize a batch of data (use a large batch size for visualization)
dataloader_viz = DataLoader(data_concentric, batch_size=256, shuffle=True)
for inputs, targets in dataloader_viz:
    break

single_feature_plt(inputs, targets)_____no_output_____

## Train a Neural ODE

We can now train a Neural ODE on the dataloader we have just created._____no_output_____#### Set up model_____no_output_____

from anode.models import ODENet
from anode.training import Trainer

hidden_dim = 32

model = ODENet(device, data_dim, hidden_dim, time_dependent=True,
               non_linearity='relu')

optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)_____no_output_____from viz.plots import get_feature_history

# Set up trainer
trainer = Trainer(model, optimizer, device)
num_epochs = 20

# Optionally record how the features evolve during training
visualize_features = True

if visualize_features:
    feature_history = get_feature_history(trainer, dataloader, inputs,
                                          targets, num_epochs)
else:
    # If we don't record feature evolution, simply train model
    trainer.train(dataloader, num_epochs)
Iteration 0/63
Loss: 0.575
Batch Accuracy: 0.438
NFE: 14
BNFE: 0
Total NFE: 14

Iteration 10/63
Loss: 0.568
Batch Accuracy: 0.516
NFE: 14
BNFE: 0
Total NFE: 14

Iteration 20/63
Loss: 0.561
Batch Accuracy: 0.422
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 30/63
Loss: 0.537
Batch Accuracy: 0.500
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 40/63
Loss: 0.482
Batch Accuracy: 0.562
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 50/63
Loss: 0.518
Batch Accuracy: 0.516
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 60/63
Loss: 0.482
Batch Accuracy: 0.562
NFE: 20
BNFE: 0
Total NFE: 20
Epoch 1: 0.508
Epoch 1: 0.535

Iteration 0/63
Loss: 0.395
Batch Accuracy: 0.750
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 10/63
Loss: 0.463
Batch Accuracy: 0.578
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 20/63
Loss: 0.392
Batch Accuracy: 0.672
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 30/63
Loss: 0.410
Batch Accuracy: 0.656
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 40/63
Loss: 0.455
Batch Accuracy: 0.656
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 50/63
Loss: 0.333
Batch Accuracy: 0.766
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 60/63
Loss: 0.376
Batch Accuracy: 0.719
NFE: 20
BNFE: 0
Total NFE: 20
Epoch 1: 0.423
Epoch 1: 0.635

Iteration 0/63
Loss: 0.348
Batch Accuracy: 0.734
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 10/63
Loss: 0.334
Batch Accuracy: 0.750
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 20/63
Loss: 0.284
Batch Accuracy: 0.828
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 30/63
Loss: 0.293
Batch Accuracy: 0.828
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 40/63
Loss: 0.225
Batch Accuracy: 0.859
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 50/63
Loss: 0.250
Batch Accuracy: 0.828
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 60/63
Loss: 0.377
Batch Accuracy: 0.672
NFE: 20
BNFE: 0
Total NFE: 20
Epoch 1: 0.295
Epoch 1: 0.803

Iteration 0/63
Loss: 0.259
Batch Accuracy: 0.859
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 10/63
Loss: 0.205
Batch Accuracy: 0.922
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 20/63
Loss: 0.249
Batch Accuracy: 0.844
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 30/63
Loss: 0.205
Batch Accuracy: 0.828
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 40/63
Loss: 0.210
Batch Accuracy: 0.844
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 50/63
Loss: 0.163
Batch Accuracy: 0.922
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 60/63
Loss: 0.205
Batch Accuracy: 0.859
NFE: 20
BNFE: 0
Total NFE: 20
Epoch 1: 0.231
Epoch 1: 0.851

Iteration 0/63
Loss: 0.193
Batch Accuracy: 0.906
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 10/63
Loss: 0.182
Batch Accuracy: 0.906
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 20/63
Loss: 0.224
Batch Accuracy: 0.812
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 30/63
Loss: 0.216
Batch Accuracy: 0.844
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 40/63
Loss: 0.188
Batch Accuracy: 0.891
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 50/63
Loss: 0.164
Batch Accuracy: 0.906
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 60/63
Loss: 0.159
Batch Accuracy: 0.906
NFE: 26
BNFE: 0
Total NFE: 26
Epoch 1: 0.191
Epoch 1: 0.881

Iteration 0/63
Loss: 0.111
Batch Accuracy: 0.938
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 10/63
Loss: 0.148
Batch Accuracy: 0.906
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 20/63
Loss: 0.202
Batch Accuracy: 0.875
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 30/63
Loss: 0.128
Batch Accuracy: 0.922
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 40/63
Loss: 0.133
Batch Accuracy: 0.938
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 50/63
Loss: 0.154
Batch Accuracy: 0.906
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 60/63
Loss: 0.143
Batch Accuracy: 0.891
NFE: 26
BNFE: 0
Total NFE: 26
Epoch 1: 0.152
Epoch 1: 0.907

Iteration 0/63
Loss: 0.116
Batch Accuracy: 0.922
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 10/63
Loss: 0.142
Batch Accuracy: 0.906
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 20/63
Loss: 0.139
Batch Accuracy: 0.906
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 30/63
Loss: 0.117
Batch Accuracy: 0.922
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 40/63
Loss: 0.092
Batch Accuracy: 0.938
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 50/63
Loss: 0.076
Batch Accuracy: 0.969
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 60/63
Loss: 0.109
Batch Accuracy: 0.969
NFE: 26
BNFE: 0
Total NFE: 26
Epoch 1: 0.118
Epoch 1: 0.935

Iteration 0/63
Loss: 0.151
Batch Accuracy: 0.891
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 10/63
Loss: 0.113
Batch Accuracy: 0.938
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 20/63
Loss: 0.109
Batch Accuracy: 0.953
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 30/63
Loss: 0.072
Batch Accuracy: 0.969
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 40/63
Loss: 0.088
Batch Accuracy: 0.938
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 50/63
Loss: 0.083
Batch Accuracy: 0.969
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 60/63
Loss: 0.065
Batch Accuracy: 0.984
NFE: 26
BNFE: 0
Total NFE: 26
Epoch 1: 0.094
Epoch 1: 0.958

Iteration 0/63
Loss: 0.084
Batch Accuracy: 0.938
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 10/63
Loss: 0.063
Batch Accuracy: 0.969
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 20/63
Loss: 0.128
Batch Accuracy: 0.922
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 30/63
Loss: 0.069
Batch Accuracy: 0.953
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 40/63
Loss: 0.090
Batch Accuracy: 0.953
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 50/63
Loss: 0.059
Batch Accuracy: 0.984
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 60/63
Loss: 0.100
Batch Accuracy: 0.953
NFE: 26
BNFE: 0
Total NFE: 26
Epoch 1: 0.076
Epoch 1: 0.969

Iteration 0/63
Loss: 0.075
Batch Accuracy: 0.953
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 10/63
Loss: 0.040
Batch Accuracy: 1.000
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 20/63
Loss: 0.080
Batch Accuracy: 0.969
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 30/63
Loss: 0.048
Batch Accuracy: 1.000
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 40/63
Loss: 0.097
Batch Accuracy: 0.953
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 50/63
Loss: 0.051
Batch Accuracy: 0.984
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 60/63
Loss: 0.059
Batch Accuracy: 0.984
NFE: 26
BNFE: 0
Total NFE: 26
Epoch 1: 0.065
Epoch 1: 0.977

Iteration 0/63
Loss: 0.054
Batch Accuracy: 0.969
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 10/63
Loss: 0.079
Batch Accuracy: 0.969
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 20/63
Loss: 0.064
Batch Accuracy: 0.969
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 30/63
Loss: 0.067
Batch Accuracy: 0.953
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 40/63
Loss: 0.030
Batch Accuracy: 1.000
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 50/63
Loss: 0.089
Batch Accuracy: 0.969
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 60/63
Loss: 0.066
Batch Accuracy: 0.969
NFE: 26
BNFE: 0
Total NFE: 26
Epoch 1: 0.059
Epoch 1: 0.979

Iteration 0/63
Loss: 0.067
Batch Accuracy: 1.000
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 10/63
Loss: 0.048
Batch Accuracy: 1.000
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 20/63
Loss: 0.054
Batch Accuracy: 1.000
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 30/63
Loss: 0.044
Batch Accuracy: 0.984
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 40/63
Loss: 0.036
Batch Accuracy: 0.984
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 50/63
Loss: 0.049
Batch Accuracy: 0.969
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 60/63
Loss: 0.071
Batch Accuracy: 0.984
NFE: 26
BNFE: 0
Total NFE: 26
Epoch 1: 0.052
Epoch 1: 0.982

Iteration 0/63
Loss: 0.052
Batch Accuracy: 0.969
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 10/63
Loss: 0.046
Batch Accuracy: 0.984
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 20/63
Loss: 0.045
Batch Accuracy: 1.000
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 30/63
Loss: 0.041
Batch Accuracy: 0.969
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 40/63
Loss: 0.016
Batch Accuracy: 1.000
NFE: 32
BNFE: 0
Total NFE: 32

Iteration 50/63
Loss: 0.066
Batch Accuracy: 0.984
NFE: 32
BNFE: 0
Total NFE: 32

Iteration 60/63
Loss: 0.046
Batch Accuracy: 0.984
NFE: 32
BNFE: 0
Total NFE: 32
Epoch 1: 0.045
Epoch 1: 0.986

Iteration 0/63
Loss: 0.039
Batch Accuracy: 0.984
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 10/63
Loss: 0.027
Batch Accuracy: 0.984
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 20/63
Loss: 0.048
Batch Accuracy: 0.984
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 30/63
Loss: 0.048
Batch Accuracy: 0.984
NFE: 32
BNFE: 0
Total NFE: 32

Iteration 40/63
Loss: 0.072
Batch Accuracy: 0.969
NFE: 26
BNFE: 0
Total NFE: 26

Iteration 50/63
Loss: 0.047
Batch Accuracy: 0.984
NFE: 32
BNFE: 0
Total NFE: 32

#### Visualize feature evolution

As can be seen, the model struggles to push the blue points out of the red circle._____no_output_____

from viz.plots import multi_feature_plt

multi_feature_plt(feature_history[::2], targets)_____no_output_____

#### Visualize ODE trajectories
We can also visualize how the trained model maps inputs to features._____no_output_____

from viz.plots import trajectory_plt

# To make the plot clearer, we will use a smaller batch of data
for small_inputs, small_targets in dataloader:
    break

trajectory_plt(model, small_inputs, small_targets, timesteps=10)_____no_output_____

#### Visualize generalization
To see how well the model generalizes we can plot how every point in the input space gets mapped to an output. If a point gets mapped to +1 it will be red, if it gets mapped to -1 it will be blue. _____no_output_____

from viz.plots import input_space_plt

input_space_plt(model)_____no_output_____

#### Losses and number of function evaluations

Finally we can visualize how the loss and the number of function evaluations (which is proportional to how long a forward pass takes) change during training._____no_output_____

plt.plot(trainer.histories['loss_history'])
plt.xlim(0, len(trainer.histories['loss_history']) - 1)
plt.ylim(0)
plt.xlabel('Iterations')
plt.ylabel('Loss')_____no_output_____plt.plot(trainer.histories['nfe_history'])
plt.xlim(0, len(trainer.histories['nfe_history']) - 1)
plt.ylim(0)
plt.xlabel('Iterations')
plt.ylabel('NFEs')_____no_output_____

## Train an Augmented Neural ODE

As can be seen, the Neural ODE model eventually learns to approximate the function, but does so at the cost of poor generalization and increased computational cost. We will now train an Augmented Neural ODE with one augmented dimension to attempt to mitigate these problems._____no_output_____

# Add 1 augmented dimension
anode = ODENet(device, data_dim, hidden_dim, augment_dim=5,
               time_dependent=True, non_linearity='relu')

optimizer_anode = torch.optim.Adam(anode.parameters(), lr=1e-3)_____no_output_____# Set up trainer
trainer_anode = Trainer(anode, optimizer_anode, device)
num_epochs = 20

# Optionally record how the features evolve during training
visualize_features = True

if visualize_features:
    feature_history = get_feature_history(trainer_anode, dataloader,
                                          inputs, targets, num_epochs)
else:
    # If we don't record feature evolution, simply train model
    trainer_anode.train(dataloader, num_epochs)
Iteration 0/63
Loss: 0.504
Batch Accuracy: 0.500
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 10/63
Loss: 0.526
Batch Accuracy: 0.500
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 20/63
Loss: 0.434
Batch Accuracy: 0.672
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 30/63
Loss: 0.431
Batch Accuracy: 0.672
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 40/63
Loss: 0.436
Batch Accuracy: 0.656
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 50/63
Loss: 0.410
Batch Accuracy: 0.703
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 60/63
Loss: 0.433
Batch Accuracy: 0.625
NFE: 20
BNFE: 0
Total NFE: 20
Epoch 1: 0.467
Epoch 1: 0.604

Iteration 0/63
Loss: 0.398
Batch Accuracy: 0.656
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 10/63
Loss: 0.283
Batch Accuracy: 0.859
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 20/63
Loss: 0.185
Batch Accuracy: 0.984
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 30/63
Loss: 0.151
Batch Accuracy: 0.969
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 40/63
Loss: 0.087
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 50/63
Loss: 0.099
Batch Accuracy: 0.938
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 60/63
Loss: 0.078
Batch Accuracy: 0.984
NFE: 20
BNFE: 0
Total NFE: 20
Epoch 1: 0.174
Epoch 1: 0.931

Iteration 0/63
Loss: 0.054
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 10/63
Loss: 0.053
Batch Accuracy: 0.984
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 20/63
Loss: 0.083
Batch Accuracy: 0.969
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 30/63
Loss: 0.052
Batch Accuracy: 0.984
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 40/63
Loss: 0.082
Batch Accuracy: 0.953
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 50/63
Loss: 0.057
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 60/63
Loss: 0.050
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20
Epoch 1: 0.059
Epoch 1: 0.991

Iteration 0/63
Loss: 0.049
Batch Accuracy: 0.984
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 10/63
Loss: 0.044
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 20/63
Loss: 0.059
Batch Accuracy: 0.984
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 30/63
Loss: 0.051
Batch Accuracy: 0.984
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 40/63
Loss: 0.045
Batch Accuracy: 0.984
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 50/63
Loss: 0.040
Batch Accuracy: 0.984
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 60/63
Loss: 0.029
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20
Epoch 1: 0.047
Epoch 1: 0.990

Iteration 0/63
Loss: 0.038
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 10/63
Loss: 0.035
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 20/63
Loss: 0.030
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 30/63
Loss: 0.048
Batch Accuracy: 0.969
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 40/63
Loss: 0.052
Batch Accuracy: 0.984
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 50/63
Loss: 0.033
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 60/63
Loss: 0.046
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20
Epoch 1: 0.039
Epoch 1: 0.993

Iteration 0/63
Loss: 0.035
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 10/63
Loss: 0.024
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 20/63
Loss: 0.053
Batch Accuracy: 0.969
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 30/63
Loss: 0.026
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 40/63
Loss: 0.047
Batch Accuracy: 0.984
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 50/63
Loss: 0.027
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 60/63
Loss: 0.029
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20
Epoch 1: 0.034
Epoch 1: 0.992

Iteration 0/63
Loss: 0.025
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 10/63
Loss: 0.025
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 20/63
Loss: 0.020
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 30/63
Loss: 0.032
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 40/63
Loss: 0.034
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 50/63
Loss: 0.042
Batch Accuracy: 0.984
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 60/63
Loss: 0.027
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20
Epoch 1: 0.029
Epoch 1: 0.994

Iteration 0/63
Loss: 0.030
Batch Accuracy: 0.984
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 10/63
Loss: 0.026
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 20/63
Loss: 0.018
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 30/63
Loss: 0.013
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 40/63
Loss: 0.020
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 50/63
Loss: 0.022
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 60/63
Loss: 0.013
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20
Epoch 1: 0.021
Epoch 1: 0.996

Iteration 0/63
Loss: 0.015
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 10/63
Loss: 0.017
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 20/63
Loss: 0.012
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 30/63
Loss: 0.010
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 40/63
Loss: 0.009
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 50/63
Loss: 0.013
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 60/63
Loss: 0.011
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20
Epoch 1: 0.016
Epoch 1: 0.996

Iteration 0/63
Loss: 0.007
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 10/63
Loss: 0.007
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 20/63
Loss: 0.008
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 30/63
Loss: 0.008
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 40/63
Loss: 0.007
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 50/63
Loss: 0.007
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 60/63
Loss: 0.020
Batch Accuracy: 0.984
NFE: 20
BNFE: 0
Total NFE: 20
Epoch 1: 0.013
Epoch 1: 0.997

Iteration 0/63
Loss: 0.012
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 10/63
Loss: 0.038
Batch Accuracy: 0.984
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 20/63
Loss: 0.010
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 30/63
Loss: 0.006
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 40/63
Loss: 0.013
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 50/63
Loss: 0.006
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 60/63
Loss: 0.024
Batch Accuracy: 0.984
NFE: 20
BNFE: 0
Total NFE: 20
Epoch 1: 0.016
Epoch 1: 0.993

Iteration 0/63
Loss: 0.009
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 10/63
Loss: 0.012
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 20/63
Loss: 0.004
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 30/63
Loss: 0.003
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 40/63
Loss: 0.008
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 50/63
Loss: 0.008
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 60/63
Loss: 0.007
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20
Epoch 1: 0.011
Epoch 1: 0.997

Iteration 0/63
Loss: 0.009
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 10/63
Loss: 0.005
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 20/63
Loss: 0.004
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 30/63
Loss: 0.024
Batch Accuracy: 0.984
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 40/63
Loss: 0.025
Batch Accuracy: 0.984
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 50/63
Loss: 0.008
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 60/63
Loss: 0.005
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20
Epoch 1: 0.013
Epoch 1: 0.993

Iteration 0/63
Loss: 0.003
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 10/63
Loss: 0.003
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 20/63
Loss: 0.017
Batch Accuracy: 0.984
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 30/63
Loss: 0.028
Batch Accuracy: 0.984
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 40/63
Loss: 0.024
Batch Accuracy: 0.984
NFE: 20
BNFE: 0
Total NFE: 20

Iteration 50/63
Loss: 0.006
Batch Accuracy: 1.000
NFE: 20
BNFE: 0
Total NFE: 20

#### Visualize feature evolution
As can be seen, the model lifts out the disk from the surrouding annulus by going into the augmented dimension._____no_output_____

from viz.plots import multi_feature_plt
plt.figure()
multi_feature_plt(feature_history, targets)_____no_output_____

#### Visualize ODE trajectories

We can visualize how the augmented model maps inputs to features._____no_output_____

from viz.plots import trajectory_plt

trajectory_plt(anode, small_inputs, small_targets, timesteps=10)_____no_output_____#### Visualize generalization
As can be seen, the model generalizes well and has captured the shape of the data._____no_output_____from viz.plots import input_space_plt

input_space_plt(anode)_____no_output_____

#### Visualize losses and NFEs

As can be seen, the Augmented Neural ODE model achieves low losses and low NFEs. This suggests it has learned to model the data with a simple flow that is easy to compute._____no_output_____

plt.plot(trainer_anode.histories['loss_history'])
plt.xlim(0, len(trainer_anode.histories['loss_history']) - 1)
plt.ylim(0)
plt.xlabel('Iterations')
plt.ylabel('Loss')_____no_output_____plt.plot(trainer_anode.histories['nfe_history'])
plt.xlim(0, len(trainer_anode.histories['nfe_history']) - 1)
plt.ylim(0)
plt.xlabel('Iterations')
plt.ylabel('NFEs')_____no_output_____


# Notebook from MonashBioinformaticsPlatform/intro-to-python-for-bioinformatics
Path: notebooks/Epilogue.ipynb

# Useful resources

The notebooks for this course are available at: https://github.com/MonashBioinformaticsPlatform/intro-to-python-for-bioinformatics/tree/bioinfosummer2017

The official Python docs are quite good: https://docs.python.org/3/tutorial/

The Data Carpentry and Software Carpentry courses: http://www.datacarpentry.org/python-ecology-lesson/ and https://swcarpentry.github.io/python-novice-inflammation/

An in-depth from beginner to more advanced concepts: http://www.python-course.eu/python3_course.php

So many *'Data Science'* MOOCs. So, so many.

Check out `numpy` (fast arrays rather than simple Python lists) and `Pandas` (DataFrames for stats, similar to `R`)._____no_output_____## Alternative ways to run Jupyter notebooks

#### Install it locally

http://jupyter.org/install.html

```sh
python3 -m venv ~/jupyter_venv
source ~/jupyter_venv/bin/activate
python3 -m pip install --upgrade pip
python3 -m pip install jupyter
jupyter notebook
```

#### Various free hosted notebook services

https://notebooks.azure.com

https://colab.research.google.com/notebook

https://try.jupyter.org/

https://cocalc.com/

_____no_output_____

<code>
import thisThe Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

</code>