Repository: kundajelab/chrombpnet (language: python)

Issue:
Improving modisco tomtom html documentation for staging
Resolving merge conflicts to get "improving_modisco_tomtom_html_documentation" into "staging" (which has the pip module code version). This is done on a separate branch for visibility as to what changes were needed. 



Discussion / hints:

Fix patch:
diff --git a/.github/workflows/dev-docker-image.yml b/.github/workflows/dev_staging-docker-image.yml
similarity index 78%
rename from .github/workflows/dev-docker-image.yml
rename to .github/workflows/dev_staging-docker-image.yml
index 0dc0f329..997de143 100755
--- a/.github/workflows/dev-docker-image.yml
+++ b/.github/workflows/dev_staging-docker-image.yml
@@ -3,13 +3,13 @@ name: Docker Image CI
 on:
   push:
     branch:        
-      - master    
+      - staging    
 jobs:
 
   build:
 
     runs-on: ubuntu-latest
-    if: GitHub.ref == 'refs/heads/master'
+    if: GitHub.ref == 'refs/heads/staging'
     steps:
     - uses: actions/checkout@v2
     - name: Build the Docker image
@@ -21,7 +21,7 @@ jobs:
               
     - name: Build the Docker image
 
-      run: docker build . --file dockerfile --tag kundajelab/chrombpnet:dev
+      run: docker build . --file dockerfile --tag kundajelab/chrombpnet:dev_staging 
       
     - name: Docker Push
-      run: docker push kundajelab/chrombpnet:dev
+      run: docker push kundajelab/chrombpnet:dev_staging 
diff --git a/LICENSE b/LICENSE
new file mode 100755
index 00000000..24836b2f
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2019 Kundaje Lab
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100755
index 00000000..c095eda7
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1,8 @@
+include requirements.txt
+include step1_download_bams_and_peaks.sh
+include step2_make_bigwigs_from_bams.sh
+include step3_get_background_regions.sh
+include step4_train_bias_model.sh
+include step5_interpret_bias_model.sh
+include step6_train_chrombpnet_model.sh
+include step7_interpret_chrombpnet_model.sh
diff --git a/README.md b/README.md
index cdd185f5..cc9745e7 100644
--- a/README.md
+++ b/README.md
@@ -6,6 +6,9 @@
 - Authors would like to thank Avanti Shrikumar and Surag Nair for their help with the project.
 - Link to a pretrained bias model trained in K562 bulk ATAC-seq - http://mitra.stanford.edu/kundaje/anusri/chrombpnet_downloads/bias.h5. You can also continue to use the bias model from chrombpnet-lite repo if that is what you have been using so far.
 
+## WARNING: If upgrading from v1.0 or v1.1 to v1.2
+Note that chrombpnet has undergone linting to generate a modular structure for release on pypi.Hard-coded script paths are no longer necessary. Please refer to the updated README (below) to ensure your script calls are compatible with v1.2
+
 ## Quick Links
 
 - [About](#chrombpnet)
@@ -25,12 +28,13 @@ ChromBPNet (shown in the image as `chrombpnet model`) is a fully convolutional n
 
 If you are interested in learning more about the detailed architectures used, please refer to the following architecture files - 
 
-- bias model: https://github.com/kundajelab/chrombpnet/blob/master/src/training/models/bpnet_model.py
-- chrombpnet model: https://github.com/kundajelab/chrombpnet/blob/master/src/training/models/chrombpnet_with_bias_model.py.
+- bias model: https://github.com/kundajelab/chrombpnet/blob/master/chrombpnet/training/models/bpnet_model.py
+- chrombpnet model: https://github.com/kundajelab/chrombpnet/blob/master/chrombpnet/training/models/chrombpnet_with_bias_model.py.
+
 
 ## Installation
 
-This section will discuss the packages needed to train a chrombpnet model. Firstly, it is recommended that you use a GPU for model training and have the necessary NVIDIA drivers already installed. Secondly there are two ways to ensure you have the necessary packages to train chrombpnet models which we detail below,
+This section will discuss the packages needed to train a chrombpnet model. Firstly, it is recommended that you use a GPU for model training and have the necessary NVIDIA drivers and CUDA already installed. You can verify that your machine is set up to use GPU's properly by executing the `nvidia-smi` command and ensuringn that the command returns information about your system GPU(s) (rather than an error). Secondly there are two ways to ensure you have the necessary packages to train chrombpnet models which we detail below,
 
 ### 1. Installation setup through Docker
 
@@ -42,24 +46,24 @@ Download and install the latest version of Docker for your platform. Here is the
 docker run -it --rm --memory=100g --gpus device=0  kundajelab/chrombpnet:dev
 ```
 
-### 2. Installation setup through Conda
-
-Download and install the latest version of Miniconda for your platform. Here is the link for the installers - <a href="https://docs.conda.io/en/latest/miniconda.html">Miniconda Installers</a>. Using Conda you can setup your own environment from scratch by following the commands in https://github.com/kundajelab/chrombpnet/blob/master/dockerfile.
-
-First create a new virtual environment and activate it as shown below
+### 2. Installation setup throuh github within a conda environment 
 
+Create a clean conda environment with python >=3.8 
 ```
-conda create --name chrombpnet python=3.7.9
+conda create -n chrombpnet python=3.8
 conda activate chrombpnet
 ```
 
-Now install the packages required by chrombpnet as follows.
+Install non-Python  requirements via conda
+```
+conda install -y -c bioconda samtools bedtools ucsc-bedgraphtobigwig
+```
+
+Git clone the staging branch of chrombpnet and install via pip
 
 ```
-conda install -y -c bioconda samtools bedtools ucsc-bedgraphtobigwig 
-git clone https://github.com/kundajelab/chrombpnet.git
-cd chrombpnet
-pip install -r requirements.txt
+git clone -b staging https://github.com/kundajelab/chrombpnet.git
+pip install -e chrombpnet
 ```
 	
 ##  Tutorial on how to train chrombpnet models
@@ -75,21 +79,21 @@ We will start by creating a directory (`data/downloads`) to download the bams an
 ```
 mkdir data
 mkdir data/downloads
-bash step1_download_bams_and_peaks.sh data/downloads
+step1_download_bams_and_peaks.sh data/downloads
 ```
 
 Following are some things to keep in mind when using custom datasets/downloads -
-- For bulk ATAC-seq/DNASE-seq datasets we use the latest <a href="https://github.com/ENCODE-DCC/atac-seq-pipeline ">ENCODE ATAC-seq protocol</a>  for peak-calling. 
+- For bulk ATAC-seq/DNASE-seq datasets we use the latest <a href="https://github.com/ENCODE-DCC/atac-seq-pipeline">ENCODE ATAC-seq protocol</a>  for peak-calling. 
 - If you are downloading the data from the ENCODE portal you can download the peaks flagged default for ATAC-seq datasets. For DNASE-seq datasets you might have to use MACS2 and follow the ENCODE ATAC-seq protocol for peak-calling.  (TODO - provide scripts to call peaks on filtered bams).
-- For paired end data we download the filtered bams and for single-end data we download the unfiltered bams from the pipeline/ENCODE portal. Please refer to the documentation below to understand the reason for this difference `src/helpers/preprocessing/`
+- For paired end data we download the filtered bams and for single-end data we download the unfiltered bams from the pipeline/ENCODE portal. Please refer to the documentation below to understand the reason for this difference `chrombpnet/helpers/preprocessing/`
 - TODO - add notes on how this will be different for scATAC.
 
 #### Step 2: Make Bigwigs from Bam files (IMPORTANT STEP! PLEASE READ CAREFULLY)
 
-We will now create unstranded bigwigs (i.e. the + and - strand ends are combined into one stranded bigwig) from the bam files (downloaded in step1) using the command below. This workflow uses the following two commands (1) `src/helpers/preprocessing/bam_to_bigwig.sh`: Considers that the given bam files are *unshifted* and does a shift of +4/-4 and (2) `src/helpers/preprocessing/analysis/build_pwm_from_bigwig.py` generates an image of the bias motif obtained from the shifted bams. 
+We will now create unstranded bigwigs (i.e. the + and - strand ends are combined into one stranded bigwig) from the bam files (downloaded in step1) using the command below. This workflow uses the following two commands (1) `bam_to_bigwig.sh`: Considers that the given bam files are *unshifted* and does a shift of +4/-4 and (2) `chrombpnet_pwm_from_bigwig` generates an image of the bias motif obtained from the shifted bams. 
 
 ```
-bash step2_make_bigwigs_from_bams.sh data/downloads/merged.bam data/downloads/K562 ATAC_PE data/downloads/hg38.fa hg38.chrom.sizes
+step2_make_bigwigs_from_bams.sh data/downloads/merged.bam data/downloads/K562 ATAC_PE data/downloads/hg38.fa hg38.chrom.sizes
 ```
 
 This command will generate two important output files - `data/downloads/K562_unstranded.bw`(unstranded bigwig file) and `data/downloads/K562_bias_pwm.png` (bias motif image). Open the `data/downloads/K562_bias_pwm.png` image generated by the script and you will see the following Tn5 motif PWM for this dataset.
@@ -98,9 +102,9 @@ This command will generate two important output files - `data/downloads/K562_uns
 
 Following are some things to keep in mind when using custom datasets/downloads -
 
-- **IMPORTANT NOTE 1:** If you are running these commands on custom experimental bam files - *read the documentation* in the directory `src/helpers/preprocessing/` and  `src/helpers/preprocessing/analysis/` to make sure you are using this worflow correctly. Always use the scripts in `src/helpers/preprocessing/analysis/` to make sure that you see Tn5 or DNASE-I bias PWM in the output image generated. If you do not see the bias motif it is likely that the bam's that you provided have a shift of some kind. Please provide only unshifted bams to the script. **Do not proceed further if you do not see a Tn5 or DNASE-I motif after this step.** 
+- **IMPORTANT NOTE 1:** If you are running these commands on custom experimental bam files - *read the documentation* in the directory `chrombpnet/helpers/preprocessing/` and  `chrombpnet/helpers/preprocessing/analysis/` to make sure you are using this worflow correctly. Always use the script in `chrombpnet_pwm_from_bigwig` to make sure that you see Tn5 or DNASE-I bias PWM in the output image generated. If you do not see the bias motif it is likely that the bam's that you provided have a shift of some kind. Please provide only unshifted bams to the script. **Do not proceed further if you do not see a Tn5 or DNASE-I motif after this step.** 
 
-- **IMPORTANT NOTE 2:** If you are running the pipeline on custom generated bigwigs (without using `src/helpers/preprocessing/`) make sure the bigwigs are unstranded and the shifts are done correctly. To check this run the scripts in `src/helpers/preprocessing/analysis/` and make sure that you see the Tn5 or DNASE-I bias PWM in the output image generated. **Do not proceed further if you do not see a Tn5 or DNASE-I motif after this step.** 
+- **IMPORTANT NOTE 2:** If you are running the pipeline on custom generated bigwigs (skipping `step2_make_bigwigs_from_bams.sh`) make sure the bigwigs are unstranded and the shifts are done correctly. To check this execute teh script `chrombpnet_pwm_from_bigwig` (you can see the arguments by running `chrombpnet_from_bigwig -h` and make sure that you see the Tn5 or DNASE-I bias PWM in the output image generated. **Do not proceed further if you do not see a Tn5 or DNASE-I motif after this step.** 
 
 - TODO - add preprocessing scripts for scATAC datasets.
 
@@ -110,9 +114,9 @@ For chrombpnet model training we split the dataset by chromosomes for training,
 
 ```
 mkdir data/splits
-python src/helpers/make_chr_splits/splits.py -o data/splits/
+chrombpnet_make_splits -o data/splits/
 ```
-
+Note: this script is a wrapper for the python file: `chrombpnet/helpers/make_chr_splits/splits.py`
 If you want to mention custom splits please edit the `splits.py` file directly and make sure that the output json formatting is consistent with the current formatting in `splits.py` (the formatting is important for all the scripts being used in this tutorial).
 
 #### Step 3: Generate background regions (non-peaks) gc-matched with the peaks
@@ -121,7 +125,6 @@ Here we will generate non-peak background regions that GC-match with the peak re
 
 Firstly, we will start by dividing the entire genome into overlapping bins of `inputlen` regions. ChromBpnet models are trained on `inputlen` of 2114, so we will divide the entire genome into overlapping bins of length of 2114 input length and calculate their gc-fraction value. 
 
-
 For convenience the genome wide buckets we created on human genome (hg38) reference can be downloaded as follows -  
 
 ```
@@ -130,22 +133,23 @@ wget http://mitra.stanford.edu/kundaje/anusri/chrombpnet_downloads/genomewide_gc
 To generate this file directly from the scripts run the command below - 
 
 ```
-python src/helpers/make_gc_matched_negatives/get_genomewide_gc_buckets/get_genomewide_gc_bins.py -g data/downloads/hg38.fa -o data/downloads/genomewide_gc_hg38_stride_1000_inputlen_2114 -f 2114 -s 1000
+chrombpnet_genomewide_gc -g data/downloads/hg38.fa -o data/downloads/genomewide_gc_hg38_stride_1000_inputlen_2114 -f 2114 -s 1000
 ```
+This is a wrapper script that calls the python file `chrombpnet/helpers/make_gc_matched_negatives/get_genomewide_gc_buckets/get_genomewide_gc_bins.py`
 
 
 Secondly, we will filter the regions from the genome-wide buckets created from the above step such that they do not fall in peak regions or blacklist regions but have similar GC-distribution as the peaks.
 
 ```
 mkdir data/negatives_data
-bash step3_get_background_regions.sh data/downloads/hg38.fa data/downloads/hg38.chrom.sizes data/downloads/blacklist.bed.gz data/downloads/overlap.bed.gz 2114 data/downloads/genomewide_gc_hg38_stride_1000_inputlen_2114.bed data/negatives_data data/splits/fold_0.json
+step3_get_background_regions.sh data/downloads/hg38.fa data/downloads/hg38.chrom.sizes data/downloads/blacklist.bed.gz data/downloads/overlap.bed.gz 2114 data/downloads/genomewide_gc_hg38_stride_1000_inputlen_2114.bed data/negatives_data data/splits/fold_0.json
 ```
 
 Following are some things to keep in mind when using custom datasets 
 
 - `data/negatives_data/negatives_with_summit.bed` is the non-peaks file we will be using for further analysis below.
-- To understand all the outputs generated by these scripts refer to the documentation at `src/helpers/make_gc_matched_negatives`. 
-- The scripts  `src/helpers/make_gc_matched_negatives` filter out peaks for which  `inputlen` (here 2114) region cannot be constructed (this can happen if the summit/center of the peak is on the edge). For custom datasets if the reference genome is very small, than using `inputlen` of 2114 can filter out a lot of peaks - in which case users are encouraged to use smaller `inputlen`.
+- To understand all the outputs generated by these scripts refer to the documentation at `chrombpnet/helpers/make_gc_matched_negatives`. 
+- The scripts  `chrombpnet/helpers/make_gc_matched_negatives` filter out peaks for which  `inputlen` (here 2114) region cannot be constructed (this can happen if the summit/center of the peak is on the edge). For custom datasets if the reference genome is very small, than using `inputlen` of 2114 can filter out a lot of peaks - in which case users are encouraged to use smaller `inputlen`.
 
 ###  Train and Evaluate Bias Model
 
@@ -158,7 +162,7 @@ We will train a bias model on the non-peak regions by running the `step4_train_b
 ```
 mkdir models
 mkdir models/bias_model
-bash step4_train_bias_model.sh data/hg38.fa data/downloads/K562_unstranded.bw data/downloads/overlap.bed.gz data/negatives_data/negatives_with_summit.bed data/splits/fold_0.json 0.5 models/bias_model
+step4_train_bias_model.sh data/hg38.fa data/downloads/K562_unstranded.bw data/downloads/overlap.bed.gz data/negatives_data/negatives_with_summit.bed data/splits/fold_0.json 0.5 models/bias_model
 
 ```
 
@@ -199,7 +203,7 @@ Once we have the subsampled peak set we will run the script below to first get i
 
 ```
 mkdir models/bias_model/interpret
-bash step5_interpret_bias_model.sh data/downloads/hg38.fa data/subsample_peaks/30K.subsample.overlap.bed models/bias_model/bias.h5 models/bias_model/interpret/
+step5_interpret_bias_model.sh data/downloads/hg38.fa data/subsample_peaks/30K.subsample.overlap.bed models/bias_model/bias.h5 models/bias_model/interpret/
 ```
 
 ###  Train and Evaluate ChromBPNet Model
@@ -212,7 +216,7 @@ We will use the bias model trained in Step 4 to regress out the effect of the bi
 
 ```
 mkdir models/chrombpnet_model
-bash step6_train_chrombpnet_model.sh data/downloads/hg38.fa data/downloads/K562_unstranded.bw data/downloads/overlap.bed.gz data/negatives_data/negatives_with_summit.bed data/splits/fold_0.json models/bias_model/bias.h5 models/chrombpnet_model ATAC_PE
+step6_train_chrombpnet_model.sh data/downloads/hg38.fa data/downloads/K562_unstranded.bw data/downloads/overlap.bed.gz data/negatives_data/negatives_with_summit.bed data/splits/fold_0.json models/bias_model/bias.h5 models/chrombpnet_model ATAC_PE
 ```
 
 The script `step4_train_bias_model.sh` runs the following five steps -  
@@ -225,7 +229,7 @@ The script `step4_train_bias_model.sh` runs the following five steps -
 NOTE: The `models/chrombpnet_model/bias_model_scaled.h5` is the bias model  in use for bias correction - this is different from the input bias model by a scaling factor on the counts head. The user can choose to use a single bias model across different datasets (we empirically observed that bias models can be transferred across datasets) - in which case the script accounts for the difference in read-depths of the current dataset and the bias model training dataset by scaling the bias models counts head.
 
 Following are some things to keep in mind when using custom datasets:
-- Note that the script `step6_train_chrombpnet_model.sh` inputs an argument `data_type` (8th argument). The user can input the following four values for this argument - `ATAC_PE, DNASE_SE, DNASE_PE, ATAC_SE`. To understand the meaning of these arguments refer to `src/helpers/preprocessing/`.
+- Note that the script `step6_train_chrombpnet_model.sh` inputs an argument `data_type` (8th argument). The user can input the following four values for this argument - `ATAC_PE, DNASE_SE, DNASE_PE, ATAC_SE`. To understand the meaning of these arguments refer to `chrombpnet/helpers/preprocessing/`.
 - If `models/chrombpnet_model/footprints/corrected_footprints_score.txt` has values greater than 0.003, the chrombpnet models are not fully corrected for the bias. This is possible if the bias model is used incorrectly (if the bias model is transferred it is likely that the transfer has failed).
 
 
@@ -237,7 +241,7 @@ NOTE: It is computationally expensive to run this step on all the peaks -  since
 
 ```
 mkdir models/chrombpnet_model/interpret
-bash step7_interpret_chrombpnet_model.sh  data/downloads/hg38.fa data/subsample_peaks/30K.subsample.overlap.bed models/chrombpnet_model/chrombpnet_wo_bias.h5 models/chrombpnet_model/interpret/
+step7_interpret_chrombpnet_model.sh  data/downloads/hg38.fa data/subsample_peaks/30K.subsample.overlap.bed models/chrombpnet_model/chrombpnet_wo_bias.h5 models/chrombpnet_model/interpret/
 ```
 
 The script outputs interpretation scores (as h5 files `models/chrombpnet_model/interpret/corrected.profile_scores.h5` and `models/chrombpnet_model/interpret/corrected.counts_scores.h5`) and then summarizes the interpretation scores into PWMs (as png images in `models/chrombpnet_model/interpret/untrimmed_logos_counts` and `models/chrombpnet_model/interpret/untrimmed_logos_profile`). Browse through the images (with prefix name `contrib_`) in both the PWM folders and make sure you only see cell-type specific motifs (here GATA, SP1) and not bias motifs (Tn5/DNASE-I). 
diff --git a/chrombpnet/__init__.py b/chrombpnet/__init__.py
new file mode 100644
index 00000000..606da1b9
--- /dev/null
+++ b/chrombpnet/__init__.py
@@ -0,0 +1,2 @@
+print("WARNING: IF upgrading from v1.0 or v1.1 to v1.2, note that chrombpnet has undergone linting to generate a modular structure for release on pypi."
+      "Hard-coded script paths are no longer necessary. Please refer to the updated README to ensure your script calls are compatible with v1.2")
diff --git a/src/training/__init__.py b/chrombpnet/evaluation/__init__.py
similarity index 100%
rename from src/training/__init__.py
rename to chrombpnet/evaluation/__init__.py
diff --git a/src/evaluation/figure_notebooks/README.md b/chrombpnet/evaluation/figure_notebooks/README.md
similarity index 100%
rename from src/evaluation/figure_notebooks/README.md
rename to chrombpnet/evaluation/figure_notebooks/README.md
diff --git a/src/evaluation/figure_notebooks/dnase_versus_atac/footprinting.ipynb b/chrombpnet/evaluation/figure_notebooks/dnase_versus_atac/footprinting.ipynb
similarity index 100%
rename from src/evaluation/figure_notebooks/dnase_versus_atac/footprinting.ipynb
rename to chrombpnet/evaluation/figure_notebooks/dnase_versus_atac/footprinting.ipynb
diff --git a/src/evaluation/figure_notebooks/subsampling/arch_compare_footprinting.ipynb b/chrombpnet/evaluation/figure_notebooks/subsampling/arch_compare_footprinting.ipynb
similarity index 100%
rename from src/evaluation/figure_notebooks/subsampling/arch_compare_footprinting.ipynb
rename to chrombpnet/evaluation/figure_notebooks/subsampling/arch_compare_footprinting.ipynb
diff --git a/src/evaluation/figure_notebooks/subsampling/bias_diff_footprinting.ipynb b/chrombpnet/evaluation/figure_notebooks/subsampling/bias_diff_footprinting.ipynb
similarity index 100%
rename from src/evaluation/figure_notebooks/subsampling/bias_diff_footprinting.ipynb
rename to chrombpnet/evaluation/figure_notebooks/subsampling/bias_diff_footprinting.ipynb
diff --git a/src/evaluation/figure_notebooks/subsampling/comparing_deepshaps.ipynb b/chrombpnet/evaluation/figure_notebooks/subsampling/comparing_deepshaps.ipynb
similarity index 100%
rename from src/evaluation/figure_notebooks/subsampling/comparing_deepshaps.ipynb
rename to chrombpnet/evaluation/figure_notebooks/subsampling/comparing_deepshaps.ipynb
diff --git a/src/evaluation/figure_notebooks/subsampling/comparing_deepshaps_new.ipynb b/chrombpnet/evaluation/figure_notebooks/subsampling/comparing_deepshaps_new.ipynb
similarity index 100%
rename from src/evaluation/figure_notebooks/subsampling/comparing_deepshaps_new.ipynb
rename to chrombpnet/evaluation/figure_notebooks/subsampling/comparing_deepshaps_new.ipynb
diff --git a/src/evaluation/figure_notebooks/subsampling/comparing_dnase_tf_new.ipynb b/chrombpnet/evaluation/figure_notebooks/subsampling/comparing_dnase_tf_new.ipynb
similarity index 100%
rename from src/evaluation/figure_notebooks/subsampling/comparing_dnase_tf_new.ipynb
rename to chrombpnet/evaluation/figure_notebooks/subsampling/comparing_dnase_tf_new.ipynb
diff --git a/src/evaluation/figure_notebooks/subsampling/comparing_jsd.ipynb b/chrombpnet/evaluation/figure_notebooks/subsampling/comparing_jsd.ipynb
similarity index 100%
rename from src/evaluation/figure_notebooks/subsampling/comparing_jsd.ipynb
rename to chrombpnet/evaluation/figure_notebooks/subsampling/comparing_jsd.ipynb
diff --git a/src/evaluation/figure_notebooks/subsampling/comparing_tfm_hits.ipynb b/chrombpnet/evaluation/figure_notebooks/subsampling/comparing_tfm_hits.ipynb
similarity index 100%
rename from src/evaluation/figure_notebooks/subsampling/comparing_tfm_hits.ipynb
rename to chrombpnet/evaluation/figure_notebooks/subsampling/comparing_tfm_hits.ipynb
diff --git a/src/evaluation/figure_notebooks/subsampling/correlation_plots_region_wise_gm12878.ipynb b/chrombpnet/evaluation/figure_notebooks/subsampling/correlation_plots_region_wise_gm12878.ipynb
similarity index 100%
rename from src/evaluation/figure_notebooks/subsampling/correlation_plots_region_wise_gm12878.ipynb
rename to chrombpnet/evaluation/figure_notebooks/subsampling/correlation_plots_region_wise_gm12878.ipynb
diff --git a/src/evaluation/figure_notebooks/subsampling/footprinting.ipynb b/chrombpnet/evaluation/figure_notebooks/subsampling/footprinting.ipynb
similarity index 100%
rename from src/evaluation/figure_notebooks/subsampling/footprinting.ipynb
rename to chrombpnet/evaluation/figure_notebooks/subsampling/footprinting.ipynb
diff --git a/src/evaluation/figure_notebooks/subsampling/get_deepshap_and_predictions.ipynb b/chrombpnet/evaluation/figure_notebooks/subsampling/get_deepshap_and_predictions.ipynb
similarity index 100%
rename from src/evaluation/figure_notebooks/subsampling/get_deepshap_and_predictions.ipynb
rename to chrombpnet/evaluation/figure_notebooks/subsampling/get_deepshap_and_predictions.ipynb
diff --git a/src/evaluation/figure_notebooks/subsampling/get_predictions.ipynb b/chrombpnet/evaluation/figure_notebooks/subsampling/get_predictions.ipynb
similarity index 100%
rename from src/evaluation/figure_notebooks/subsampling/get_predictions.ipynb
rename to chrombpnet/evaluation/figure_notebooks/subsampling/get_predictions.ipynb
diff --git a/src/evaluation/figure_notebooks/subsampling/get_predictions_bias.ipynb b/chrombpnet/evaluation/figure_notebooks/subsampling/get_predictions_bias.ipynb
similarity index 100%
rename from src/evaluation/figure_notebooks/subsampling/get_predictions_bias.ipynb
rename to chrombpnet/evaluation/figure_notebooks/subsampling/get_predictions_bias.ipynb
diff --git a/src/evaluation/figure_notebooks/subsampling/viz_sequence.py b/chrombpnet/evaluation/figure_notebooks/subsampling/viz_sequence.py
similarity index 100%
rename from src/evaluation/figure_notebooks/subsampling/viz_sequence.py
rename to chrombpnet/evaluation/figure_notebooks/subsampling/viz_sequence.py
diff --git a/src/evaluation/interpret/README.md b/chrombpnet/evaluation/interpret/README.md
similarity index 84%
rename from src/evaluation/interpret/README.md
rename to chrombpnet/evaluation/interpret/README.md
index aecc3e39..1cbc21ac 100644
--- a/src/evaluation/interpret/README.md
+++ b/chrombpnet/evaluation/interpret/README.md
@@ -6,13 +6,13 @@ The scripts in this folder are used to do get sequence contribution scores for t
 ## Usage
 
 ```
-python interpret.py -g [genome_fasta] -r [regions] -m [model_h5] -o [output_prefix] -d [debug_chr] -p [profile_or_counts]
+chrombpne_deepshap -g [genome_fasta] -r [regions] -m [model_h5] -o [output_prefix] -d [debug_chr] -p [profile_or_counts]
 ```
 
 ## Example Usage
 
 ```
-python interpret.py -g /path/to/genome.fasta -r /path/to/regions.bed -m /path/to/model.h5 -o /path/to/output_dir/output_prefix -p counts profiles
+chrombpnet_deepshap -g /path/to/genome.fasta -r /path/to/regions.bed -m /path/to/model.h5 -o /path/to/output_dir/output_prefix -p counts profiles
 ```
 
 ## Input Format
@@ -34,3 +34,7 @@ The following two files are created using the `output_prefix` as prefix for the
     - `projected_shap` key consists of values obtained by multiplying `shap` values with `raw` values. These values will be used in building browser tracks.
 
 - `output_prefix`.count_scores.h5: A h5 file containing a dictionary with contribution scores for the count head of the chrombpnet model. Has similar structure as the `output_prefix`.profile_scores.h5.
+
+- `output_prefix`.interpreted_regions.bed: A bed file with regions used for interpretations. The script filters regions whose resulting sequences dont have the same length as `input_len` inferred from the model.  This bed file might have regions fewer than `regions` provided as input. 
+
+
diff --git a/src/training/data_generators/__init__.py b/chrombpnet/evaluation/interpret/__init__.py
similarity index 100%
rename from src/training/data_generators/__init__.py
rename to chrombpnet/evaluation/interpret/__init__.py
diff --git a/chrombpnet/evaluation/interpret/input_utils.py b/chrombpnet/evaluation/interpret/input_utils.py
new file mode 100644
index 00000000..3d5e1e87
--- /dev/null
+++ b/chrombpnet/evaluation/interpret/input_utils.py
@@ -0,0 +1,38 @@
+import os
+import sys
+import os
+import sys
+import tensorflow as tf
+import numpy as np
+import chrombpnet.training.utils.losses as losses
+from chrombpnet.training.utils.data_utils import one_hot
+from tensorflow.keras.utils import get_custom_objects
+from tensorflow.keras.models import load_model
+
+
+def get_seq(peaks_df, genome, width):
+    """
+    Same as get_cts, but fetches sequence from a given genome.
+    """
+    vals = []
+    peaks_used = []
+    for i, r in peaks_df.iterrows():
+        sequence = str(genome[r['chr']][(r['start']+r['summit'] - width//2):(r['start'] + r['summit'] + width//2)])
+        if len(sequence) == width:
+            vals.append(sequence)
+            peaks_used.append(True)
+        else:
+            peaks_used.append(False)
+
+    return one_hot.dna_to_one_hot(vals), np.array(peaks_used)
+
+
+def load_model_wrapper(args):
+    # read .h5 model
+    custom_objects={"multinomial_nll": losses.multinomial_nll, "tf": tf}    
+    get_custom_objects().update(custom_objects)    
+    model=load_model(args.model_h5)
+    print("got the model")
+    model.summary()
+    return model
+
diff --git a/src/evaluation/interpret/interpret.py b/chrombpnet/evaluation/interpret/interpret.py
similarity index 85%
rename from src/evaluation/interpret/interpret.py
rename to chrombpnet/evaluation/interpret/interpret.py
index 5b47410d..014f3608 100644
--- a/src/evaluation/interpret/interpret.py
+++ b/chrombpnet/evaluation/interpret/interpret.py
@@ -6,16 +6,13 @@
 import tensorflow as tf
 import pandas as pd
 import shap
-from tensorflow import keras
-from tensorflow.keras.utils import get_custom_objects
-from tensorflow.keras.models import load_model
 import pyfaidx
 import shutil
 import errno
 import os
 import argparse
-import shap_utils 
-import context
+import chrombpnet.evaluation.interpret.shap_utils as shap_utils
+import chrombpnet.evaluation.interpret.input_utils as input_utils
 
 NARROWPEAK_SCHEMA = ["chr", "start", "end", "1", "2", "3", "4", "5", "6", "summit"]
 
@@ -35,15 +32,6 @@ def fetch_interpret_args():
     args = parser.parse_args()
     return args
 
-def load_model_wrapper(args):
-    # read .h5 model
-    custom_objects={"multinomial_nll": context.losses.multinomial_nll, "tf": tf}    
-    get_custom_objects().update(custom_objects)    
-    model=load_model(args.model_h5)
-    print("got the model")
-    model.summary()
-    return model
-
 
 def generate_shap_dict(seqs, scores):
     assert(seqs.shape==scores.shape)
@@ -126,12 +114,8 @@ def main():
 
     if args.debug_chr:
         regions_df = regions_df[regions_df['chr'].isin(args.debug_chr)]
-        regions_df.to_csv("{}.interpreted_regions.bed".format(args.output_prefix), header=False, sep='\t')
-    else:
-        # copy regions bed to output directory
-        shutil.copy(args.regions, "{}.interpreted_regions.bed".format(args.output_prefix))
-
-    model = load_model_wrapper(args)
+    
+    model = input_utils.load_model_wrapper(args)
  
     # infer input length
     inputlen = model.input_shape[1] # if bias model (1 input only)
@@ -139,11 +123,14 @@ def main():
 
     # load sequences
     # NOTE: it will pull out sequences of length inputlen
-    #       centered at the summit (start + 10th column)
+    #       centered at the summit (start + 10th column) and peaks used after filtering
+
     genome = pyfaidx.Fasta(args.genome)
-    seqs = context.get_seq(regions_df, genome, inputlen)
+    seqs, peaks_used = input_utils.get_seq(regions_df, genome, inputlen)
     genome.close()
 
+    regions_df[peaks_used].to_csv("{}.interpreted_regions.bed".format(args.output_prefix), header=False, sep='\t')
+
     interpret(model, seqs, args.output_prefix, args.profile_or_counts)
 
 if __name__ == '__main__':
diff --git a/src/evaluation/interpret/shap_utils.py b/chrombpnet/evaluation/interpret/shap_utils.py
similarity index 100%
rename from src/evaluation/interpret/shap_utils.py
rename to chrombpnet/evaluation/interpret/shap_utils.py
diff --git a/src/evaluation/invivo_footprints/README.md b/chrombpnet/evaluation/invivo_footprints/README.md
similarity index 100%
rename from src/evaluation/invivo_footprints/README.md
rename to chrombpnet/evaluation/invivo_footprints/README.md
diff --git a/src/evaluation/make_bigwigs/README.md b/chrombpnet/evaluation/invivo_footprints/__init__.py
similarity index 100%
rename from src/evaluation/make_bigwigs/README.md
rename to chrombpnet/evaluation/invivo_footprints/__init__.py
diff --git a/src/evaluation/invivo_footprints/figures/scoredist_0.png b/chrombpnet/evaluation/invivo_footprints/figures/scoredist_0.png
similarity index 100%
rename from src/evaluation/invivo_footprints/figures/scoredist_0.png
rename to chrombpnet/evaluation/invivo_footprints/figures/scoredist_0.png
diff --git a/src/evaluation/invivo_footprints/run_tfmodisco.py b/chrombpnet/evaluation/invivo_footprints/run_tfmodisco.py
similarity index 100%
rename from src/evaluation/invivo_footprints/run_tfmodisco.py
rename to chrombpnet/evaluation/invivo_footprints/run_tfmodisco.py
diff --git a/src/evaluation/invivo_footprints/script.sh b/chrombpnet/evaluation/invivo_footprints/script.sh
similarity index 100%
rename from src/evaluation/invivo_footprints/script.sh
rename to chrombpnet/evaluation/invivo_footprints/script.sh
diff --git a/src/evaluation/invivo_footprints/script_new.sh b/chrombpnet/evaluation/invivo_footprints/script_new.sh
similarity index 100%
rename from src/evaluation/invivo_footprints/script_new.sh
rename to chrombpnet/evaluation/invivo_footprints/script_new.sh
diff --git a/src/evaluation/invivo_footprints/tf_modiscohits.py b/chrombpnet/evaluation/invivo_footprints/tf_modiscohits.py
similarity index 99%
rename from src/evaluation/invivo_footprints/tf_modiscohits.py
rename to chrombpnet/evaluation/invivo_footprints/tf_modiscohits.py
index 9b95430a..1a0f0a79 100644
--- a/src/evaluation/invivo_footprints/tf_modiscohits.py
+++ b/chrombpnet/evaluation/invivo_footprints/tf_modiscohits.py
@@ -3,7 +3,7 @@
 import pandas as pd
 from modisco.hit_scoring import densityadapted_hitscoring
 from modisco.util import compute_per_position_ic
-import run_tfmodisco as run_tfmodisco
+import chrombpnet.evaluation.invivo_footprints.run_tfmodisco as run_tfmodisco
 import click
 
 def import_tfmodisco_hits(hits_bed):
diff --git a/src/helpers/data_generator_examples/README.md b/chrombpnet/evaluation/make_bigwigs/README.md
similarity index 100%
rename from src/helpers/data_generator_examples/README.md
rename to chrombpnet/evaluation/make_bigwigs/README.md
diff --git a/src/helpers/hyperparameters/README.md b/chrombpnet/evaluation/make_bigwigs/__init__.py
similarity index 100%
rename from src/helpers/hyperparameters/README.md
rename to chrombpnet/evaluation/make_bigwigs/__init__.py
diff --git a/src/evaluation/make_bigwigs/bigwig_helper.py b/chrombpnet/evaluation/make_bigwigs/bigwig_helper.py
similarity index 100%
rename from src/evaluation/make_bigwigs/bigwig_helper.py
rename to chrombpnet/evaluation/make_bigwigs/bigwig_helper.py
diff --git a/src/evaluation/make_bigwigs/importance_hdf5_to_bigwig.py b/chrombpnet/evaluation/make_bigwigs/importance_hdf5_to_bigwig.py
similarity index 96%
rename from src/evaluation/make_bigwigs/importance_hdf5_to_bigwig.py
rename to chrombpnet/evaluation/make_bigwigs/importance_hdf5_to_bigwig.py
index 827b885d..2fb04e13 100644
--- a/src/evaluation/make_bigwigs/importance_hdf5_to_bigwig.py
+++ b/chrombpnet/evaluation/make_bigwigs/importance_hdf5_to_bigwig.py
@@ -2,7 +2,7 @@
 import pyBigWig
 import numpy as np
 import deepdish
-import bigwig_helper
+import chrombpnet.evaluation.make_bigwig.bigwig_helper as bigwig_helper
 
 # need full paths!
 parser = argparse.ArgumentParser(description="Convert importance scores in hdf5 format to bigwig. The output can be visualised using WashU Epigenome Browser as a dynseq track. Please read all parameter argument requirements. PROVIDE ABSOLUTE PATHS!")
diff --git a/src/evaluation/make_bigwigs/predict_to_bigwig.py b/chrombpnet/evaluation/make_bigwigs/predict_to_bigwig.py
similarity index 88%
rename from src/evaluation/make_bigwigs/predict_to_bigwig.py
rename to chrombpnet/evaluation/make_bigwigs/predict_to_bigwig.py
index 69a0ef94..2a5e5028 100644
--- a/src/evaluation/make_bigwigs/predict_to_bigwig.py
+++ b/chrombpnet/evaluation/make_bigwigs/predict_to_bigwig.py
@@ -1,14 +1,15 @@
-import tensorflow as tf
-from tensorflow import keras
 import argparse
 import pyBigWig
 import numpy as np
 import pandas as pd
-import bigwig_helper
 import pyfaidx
-import sys
-from context import data_utils as data_utils
-from context import load_model_wrapper as load_model_wrapper
+from tensorflow.keras.utils import get_custom_objects
+from tensorflow.keras.models import load_model
+import tensorflow as tf
+import chrombpnet.evaluation.make_bigwigs.bigwig_helper as bigwig_helper
+import chrombpnet.training.utils.losses as losses
+import chrombpnet.training.utils.data_utils as data_utils 
+import chrombpnet.training.utils.one_hot as one_hot
 
 NARROWPEAK_SCHEMA = ["chr", "start", "end", "1", "2", "3", "4", "5", "6", "summit"]
 
@@ -33,6 +34,14 @@ def softmax(x, temp=1):
     norm_x = x - np.mean(x,axis=1, keepdims=True)
     return np.exp(temp*norm_x)/np.sum(np.exp(temp*norm_x), axis=1, keepdims=True)
 
+def load_model_wrapper(model_hdf5):
+    # read .h5 model
+    custom_objects={"multinomial_nll":losses.multinomial_nll, "tf": tf}    
+    get_custom_objects().update(custom_objects)    
+    model=load_model(model_hdf5)
+    print("got the model")
+    model.summary()
+    return model
 
 model_chrombpnet_nb = load_model_wrapper(model_hdf5=args.chrombpnet_model_nb)
 model_chrombpnet = load_model_wrapper(model_hdf5=args.chrombpnet_model)
diff --git a/src/evaluation/marginal_footprints/README.md b/chrombpnet/evaluation/marginal_footprints/README.md
similarity index 87%
rename from src/evaluation/marginal_footprints/README.md
rename to chrombpnet/evaluation/marginal_footprints/README.md
index 9cfcee2a..5deefb96 100644
--- a/src/evaluation/marginal_footprints/README.md
+++ b/chrombpnet/evaluation/marginal_footprints/README.md
@@ -5,13 +5,13 @@ The scripts in this folder provide marginal footprints for a given motif and bac
 ## Usage
 
 ```
-python marginal_footprinting.py -g [genome_fasta] -r [regions] -chr [test_chr] -m [model_h5] -bs [batch_size] -o [output_prefix] -pwm_f [motifs_to_pwm_file] -mo [motifs] --ylim (min-y, max-y)
+chrombpnet_marginal_footprints -g [genome_fasta] -r [regions] -chr [test_chr] -m [model_h5] -bs [batch_size] -o [output_prefix] -pwm_f [motifs_to_pwm_file] -mo [motifs] --ylim (min-y, max-y)
 ```
 
 ## Example Usage
 
 ```
-python marginal_footprinting.py -g /path/to/genome_fasta -r /path/to/bed_file -chr chr1 -m /path/to/model.h5 -o /path/to/output_dir/outputprefix -pwm_f motif_to_pwm.tsv -mo CTCF,RUNX
+chrombpnet_marginal_footprints -g /path/to/genome_fasta -r /path/to/bed_file -chr chr1 -m /path/to/model.h5 -o /path/to/output_dir/outputprefix -pwm_f motif_to_pwm.tsv -mo CTCF,RUNX
 ```
 
 ## Input Format
diff --git a/src/training/data_generators/README.md b/chrombpnet/evaluation/marginal_footprints/__init__.py
similarity index 100%
rename from src/training/data_generators/README.md
rename to chrombpnet/evaluation/marginal_footprints/__init__.py
diff --git a/src/evaluation/marginal_footprints/marginal_footprinting.py b/chrombpnet/evaluation/marginal_footprints/marginal_footprinting.py
similarity index 89%
rename from src/evaluation/marginal_footprints/marginal_footprinting.py
rename to chrombpnet/evaluation/marginal_footprints/marginal_footprinting.py
index 1d75e1c2..e09cfe76 100644
--- a/src/evaluation/marginal_footprints/marginal_footprinting.py
+++ b/chrombpnet/evaluation/marginal_footprints/marginal_footprinting.py
@@ -12,14 +12,28 @@
 import matplotlib.pyplot as plt
 import tensorflow as tf
 import argparse
-import context
 import json
+import chrombpnet.training.utils.losses as losses
+from chrombpnet.training.utils.data_utils import get_seq as get_seq
+import chrombpnet.training.utils.one_hot as one_hot
+from tensorflow.keras.utils import get_custom_objects
+from tensorflow.keras.models import load_model
 
 
 NARROWPEAK_SCHEMA = ["chr", "start", "end", "1", "2", "3", "4", "5", "6", "summit"]
 PWM_SCHEMA = ["MOTIF_NAME", "MOTIF_PWM_FWD"]
 
 
+def load_model_wrapper(args):
+    # read .h5 model
+    custom_objects={"multinomial_nll":losses.multinomial_nll, "tf": tf}    
+    get_custom_objects().update(custom_objects)    
+    model=load_model(args.model_h5)
+    print("got the model")
+    model.summary()
+    return model
+
+
 def fetch_footprinting_args():
     parser=argparse.ArgumentParser(description="get marginal footprinting for given model and given motifs")
     parser.add_argument("-g", "--genome", type=str, required=True, help="Genome fasta")
@@ -50,7 +64,7 @@ def get_footprint_for_motif(seqs, motif, model, inputlen, batch_size):
     midpoint=inputlen//2
 
     w_mot_seqs = seqs.copy()
-    w_mot_seqs[:, midpoint-len(motif)//2:midpoint-len(motif)//2+len(motif)] = context.one_hot.dna_to_one_hot([motif])
+    w_mot_seqs[:, midpoint-len(motif)//2:midpoint-len(motif)//2+len(motif)] = one_hot.dna_to_one_hot([motif])
 
     # midpoint of motif is the midpoint of sequence
     pred_output=model.predict(w_mot_seqs, batch_size=batch_size, verbose=True)
@@ -76,7 +90,7 @@ def main():
     print(pwm_df)
     genome_fasta = pyfaidx.Fasta(args.genome)
 
-    model=context.load_model_wrapper(args)
+    model=load_model_wrapper(args)
     inputlen = model.input_shape[1] 
     outputlen = model.output_shape[0][1] 
     print("inferred model inputlen: ", inputlen)
@@ -87,7 +101,7 @@ def main():
 
     regions_df = pd.read_csv(args.regions, sep='\t', names=NARROWPEAK_SCHEMA)
     regions_subsample = regions_df[(regions_df["chr"].isin(chroms_to_keep))]
-    regions_seqs = context.get_seq(regions_subsample, genome_fasta, inputlen)
+    regions_seqs = get_seq(regions_subsample, genome_fasta, inputlen)
 
     footprints_at_motifs = {}
 
diff --git a/src/evaluation/marginal_footprints/motif_to_pwm.tsv b/chrombpnet/evaluation/marginal_footprints/motif_to_pwm.tsv
similarity index 100%
rename from src/evaluation/marginal_footprints/motif_to_pwm.tsv
rename to chrombpnet/evaluation/marginal_footprints/motif_to_pwm.tsv
diff --git a/chrombpnet/evaluation/modisco/README.md b/chrombpnet/evaluation/modisco/README.md
new file mode 100644
index 00000000..deb49188
--- /dev/null
+++ b/chrombpnet/evaluation/modisco/README.md
@@ -0,0 +1,45 @@
+
+# Scripts to do MODSICO on deepshap output of ChromBPNet and generate a html link for the outputs with tomtom annotations
+
+The scripts in this folder do the following three steps (1)  Do de-novo motif discovery on the deepshap output of chrombpnet using MODISCO (run_modisco.py) (2) Annotate the motifs using TOMTOM (fetch_tomtom.py) and (3) Summarize the output to a html format (visualize_motif_matches.py). 
+So a requirement for this script is that the outputs generated from step 2 are html hostable. If you dont to host the results online you can remove the visualize_motif_matches.py from the run.sh script below. An example html link will look like this http://mitra.stanford.edu/kundaje/oak/projects/chromatin-atlas-2022/modisco/DNASE/ENCSR000EMA/ranked_feb15/profile.motifs.html.
+
+## Usage
+
+```
+modisco.sh [scores_prefix] [output_dir] [score_type] [seqlets] [crop] [meme_db] [meme_logos] [vier_logos] [vier_html] [html_link]
+```
+
+The following assumptions are made with this script - make changes accordingly if the assumptions dont hold.
+
+- The following scripts are used on the output of `chrombpnet_deepshap`. 
+
+## Example Usage
+
+```
+modisco.sh /path/to/deepshap_scores/ /path/to/store/output/ counts_or_profiles 200000 1000 [meme_db] [meme_logos] [vier_logos] [vier_html] [html_link]
+```
+
+## Input Format
+
+- scores_prefix: This is the `output_prefix` used with `chrombpnet_deepshap`. 
+- score_type: This is either set to `counts` or `profile`.
+- output_dir: Path to a directory to store the output files. The script assumes that the directory already exists. Look at the output format section below to understand the files generated.
+- seqlets: Number of seqlets to use for modisco run. If using the most recent dev version of MODISCO this can be set to 200K. If using older version set to 50K. You can test the working of the script with a much smaller value - as this decides the runtime of the script.
+- crop: An integer value representing the crop length to use on the chrombpnet input. In chrombpnet we get contribution scores for 2114 length input but we will run modisco on only 1000 length input. So the default value for this parameter is set to 1000. We do this to avoid catching "AT" rich nucleosome motifs that occur more frequently on the flanks of the 2114 length input.
+- meme_db: Path to a txt file containing the meme motifs letter probability matrix. Text file to download - http://mitra.stanford.edu/kundaje/surag/resources/motif_archetypes/pfm_meme_format/motifs.meme.txt
+- meme_logos: Path to a directory containing meme pfms - Directory to download - http://mitra.stanford.edu/kundaje/surag/resources/motif_archetypes/pfm/
+- vier_logos: A directory with images for the pfms provided in `meme_logos`. If the image is not already present the script creates that image, so it is okay is this is an empty directory. This can be a database of meme images you can share across projects. Make sure that this directory is hostable if you are interedted in viewing the results in a html link. 
+- vier_html: An html link to `vier_logos` folder. These links are used in `score_type.motifs.html` page created below in output format section. 
+- html_link: An html link to `untrimmed_logos`. This is one of the outputs generated by run.sh. So you need to eitheir make sure output_dir/trimmed_logos is html hostable or you can copy `untrimmed_logos`  to the directory of the  html link you set here.
+
+
+## Output Format
+
+- modisco_results_allChroms_`score_type`.hdf5: Modisco output `hdf5` file.
+- seqlets_`score_type`.txt: 
+- `score_type`.tomtom.tsv: Tomom output.
+- `score_type`.motifs.html: An html link where the modisco motifs are ranked based on their frequency. This html link will host html images provided in `html_link` and `vier_html`. 
+- `untrimmed_logos_profile` or `untrimmed_logos_counts`: This directory will be created in `output_dir` path provided depending on `score_type`. This directory will store the motif images that are not trimmed.
+- `trimmed_logos`: This directory will be created in `output_dir` path provided. This directory wil store the motif images that are trimmed based on the default threshold of 0.3 used in the scripts. Make sure this directory is hostable.
+
diff --git a/chrombpnet/evaluation/modisco/__init__.py b/chrombpnet/evaluation/modisco/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/src/evaluation/modisco/fetch_tomtom.py b/chrombpnet/evaluation/modisco/fetch_tomtom.py
similarity index 99%
rename from src/evaluation/modisco/fetch_tomtom.py
rename to chrombpnet/evaluation/modisco/fetch_tomtom.py
index 3ae467c1..9efe2877 100644
--- a/src/evaluation/modisco/fetch_tomtom.py
+++ b/chrombpnet/evaluation/modisco/fetch_tomtom.py
@@ -96,8 +96,7 @@ def fetch_tomtom_matches(ppm, cwm, background=[0.25, 0.25, 0.25, 0.25], tomtom_e
     return r
 
 
-if __name__=="__main__":
-
+def main(): 
     args = fetch_tomtom_args()
 
     modisco_results = h5py.File(args.modisco_h5py, 'r')
@@ -152,4 +151,6 @@ def fetch_tomtom_matches(ppm, cwm, background=[0.25, 0.25, 0.25, 0.25], tomtom_e
             # when fewer than n matches are found
             if len(r) != args.top_n_matches:
                 f.write("\t\t"*(args.top_n_matches-len(r)))
-            f.write("\n")
\ No newline at end of file
+            f.write("\n")
+if __name__=="__main__":
+    main()
diff --git a/chrombpnet/evaluation/modisco/modisco.sh b/chrombpnet/evaluation/modisco/modisco.sh
new file mode 100644
index 00000000..4c8bcb5d
--- /dev/null
+++ b/chrombpnet/evaluation/modisco/modisco.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+# exit when any command fails
+set -e
+
+# keep track of the last executed command
+trap 'last_command=$current_command; current_command=$BASH_COMMAND' DEBUG
+# echo an error message before exiting
+trap 'echo "\"${last_command}\" command filed with exit code $?."' EXIT
+
+
+scores_prefix=${1?param missing - scores_prefix}
+output_dir=${2?param missing - output_dir}
+score_type=${3?param missing - score_type}
+seqlets=${4?param missing - seqlets}
+crop=${5?param missing - crop} 
+meme_db=${6?param missing - meme_db}
+meme_logos=${7?param missing - meme_logos}
+vier_logos=${8?param_missing - vier_logos}
+vier_html=${9?param_missing - vier_html}
+html_link=${10?param_missing - html_link}
+
+chrombpnet_modisco -s $scores_prefix -p $score_type -o $output_dir -m $seqlets -c $crop
+chrombpnet_tomtom_hits -m $output_dir/modisco_results_allChroms_counts.hdf5 -o $output_dir/$score_type.tomtom.tsv -d $meme_db -n 10 -th 0.3
+chrombpnet_visualize_motif_matches -m $output_dir/modisco_results_allChroms_counts.hdf5 -t $output_dir/$score_type.tomtom.tsv -o $output_dir \
+     -vd $vier_logos -th 0.3 -hl $html_link -vhl $vier_html \
+      -s $score_type -d $meme_logos
+
diff --git a/src/evaluation/modisco/run_modisco.py b/chrombpnet/evaluation/modisco/run_modisco.py
similarity index 99%
rename from src/evaluation/modisco/run_modisco.py
rename to chrombpnet/evaluation/modisco/run_modisco.py
index 8a731903..5d38f890 100644
--- a/src/evaluation/modisco/run_modisco.py
+++ b/chrombpnet/evaluation/modisco/run_modisco.py
@@ -45,8 +45,8 @@ def save_plot(weights, dst_fname):
 
     plt.savefig(dst_fname)
 
-if __name__=="__main__":
 
+def main():
     args = fetch_modisco_args()    
 
     # check if the output directory exists
@@ -157,3 +157,5 @@ def save_plot(weights, dst_fname):
         save_plot(pattern["sequence"].fwd,
                   os.path.join(args.output_dir, "untrimmed_logos_"+scoring_type, 'sequence_{}.png'.format(idx)))
 
+if __name__=="__main__":
+    main()
diff --git a/src/evaluation/modisco/visualize_motif_matches.py b/chrombpnet/evaluation/modisco/visualize_motif_matches.py
similarity index 99%
rename from src/evaluation/modisco/visualize_motif_matches.py
rename to chrombpnet/evaluation/modisco/visualize_motif_matches.py
index e01cf160..15ccc3be 100644
--- a/src/evaluation/modisco/visualize_motif_matches.py
+++ b/chrombpnet/evaluation/modisco/visualize_motif_matches.py
@@ -82,8 +82,7 @@ def create_modisco_logos(modisco_file,modisco_logo_dir, trim_threshold, score_ty
                         path=modisco_logo_dir + "/" + score_type + '.' + pattern_name + '.cwm.rev.png')
 
 
-if __name__=="__main__":
-
+def main():
     args = fetch_viz_args()
 
     score_type=args.score_type
@@ -148,7 +147,9 @@ def create_modisco_logos(modisco_file,modisco_logo_dir, trim_threshold, score_ty
                                                  ), index=False)
 
 
-print(tomtom_df.head())
+    print(tomtom_df.head())
+if __name__=="__main__":
+    main()
 
 
 
diff --git a/src/evaluation/variant_effect_prediction/README.md b/chrombpnet/evaluation/variant_effect_prediction/README.md
similarity index 97%
rename from src/evaluation/variant_effect_prediction/README.md
rename to chrombpnet/evaluation/variant_effect_prediction/README.md
index 391491ec..b02e282d 100644
--- a/src/evaluation/variant_effect_prediction/README.md
+++ b/chrombpnet/evaluation/variant_effect_prediction/README.md
@@ -6,7 +6,7 @@ The scripts in this folder are used to do variant effect prediction using chromb
 ## Usage
 
 ```
-python snp_scoring.py -i [snp_data_tsv] -g [genome_fasta] -m [model_hdf5] -o [output_dir] -bs [batch_size] -dm [debug_mode_on]
+chrombpnet_score_snps -i [snp_data_tsv] -g [genome_fasta] -m [model_hdf5] -o [output_dir] -bs [batch_size] -dm [debug_mode_on]
 ```
 
 The following assumptions are made with this script - make changes accordingly if the assumptions dont hold.
@@ -23,7 +23,7 @@ The following assumptions are made with this script - make changes accordingly i
 ## Example Usage
 
 ```
-python snp_scoring.py -i /mnt/lab_data2/anusri/variant_effect_prediction_example/subsample_test.csv -g /mnt/data/male.hg19.fa -m /path/to/model.hdf5 -o /path/to/store/output -bs 64
+chrombpnet_score_snps -i /mnt/lab_data2/anusri/variant_effect_prediction_example/subsample_test.csv -g /mnt/data/male.hg19.fa -m /path/to/model.hdf5 -o /path/to/store/output -bs 64
 ```
 
 ## Input Format
diff --git a/chrombpnet/evaluation/variant_effect_prediction/__init__.py b/chrombpnet/evaluation/variant_effect_prediction/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/src/evaluation/variant_effect_prediction/script.sh b/chrombpnet/evaluation/variant_effect_prediction/script.sh
similarity index 100%
rename from src/evaluation/variant_effect_prediction/script.sh
rename to chrombpnet/evaluation/variant_effect_prediction/script.sh
diff --git a/src/evaluation/variant_effect_prediction/snp_generator.py b/chrombpnet/evaluation/variant_effect_prediction/snp_generator.py
similarity index 95%
rename from src/evaluation/variant_effect_prediction/snp_generator.py
rename to chrombpnet/evaluation/variant_effect_prediction/snp_generator.py
index c6ab1054..9b688d17 100644
--- a/src/evaluation/variant_effect_prediction/snp_generator.py
+++ b/chrombpnet/evaluation/variant_effect_prediction/snp_generator.py
@@ -3,7 +3,7 @@
 import numpy as np
 import math
 import pyfaidx
-import one_hot
+from chrombpnet.training.utils import one_hot
 
 class SNPGenerator(Sequence):
     def __init__(self,
diff --git a/src/evaluation/variant_effect_prediction/snp_scoring.py b/chrombpnet/evaluation/variant_effect_prediction/snp_scoring.py
similarity index 93%
rename from src/evaluation/variant_effect_prediction/snp_scoring.py
rename to chrombpnet/evaluation/variant_effect_prediction/snp_scoring.py
index fddfca45..e8b501fc 100644
--- a/src/evaluation/variant_effect_prediction/snp_scoring.py
+++ b/chrombpnet/evaluation/variant_effect_prediction/snp_scoring.py
@@ -1,11 +1,11 @@
-from snp_generator import SNPGenerator
+from chrombpnet.evaluation.variant_effect_prediction.snp_generator import SNPGenerator
 from scipy.spatial.distance import jensenshannon
 from tensorflow.keras.utils import get_custom_objects
 from tensorflow.keras.models import load_model
+import chrombpnet.training.utils.losses as losses
 import pandas as pd
 import os
 import argparse
-import losses
 import numpy as np
 import pickle as pkl
 
@@ -29,13 +29,13 @@ def softmax(x, temp=1):
 
 def load_model_wrapper(args):
     # read .h5 model
-    custom_objects={"MultichannelMultinomialNLL": losses.MultichannelMultinomialNLL}    
+    custom_objects={"tf": tf, "multinomial_nll":losses.multinomial_nll}    
     get_custom_objects().update(custom_objects)    
     model=load_model(args.model_h5)
     print("model loaded succesfully")
     return model
 
-def fetch_snp_predictions(model,snp_regions, inputlen, genome_fasta, batch_size, debug_mode_on=False):
+def fetch_snp_predictions(model, snp_regions, inputlen, genome_fasta, batch_size, debug_mode_on=False):
     '''
     Returns model predictions (counts and profile probability predictions) at the given reference and alternate snp alleles.
     Please note that if the SNP location is at the edge - i.e we are unable to form a given inputlen of sequence - we skip predictions at this SNP
@@ -108,8 +108,7 @@ def predict_snp_effect_scores(rsids, ref_count_preds, alt_count_preds, ref_prob_
     return log_counts_diff, log_probs_diff_abs_sum, probs_jsd_diff
 
 
-if __name__=="__main__":
-
+def main():
     args = fetch_variant_args()
     debug_mode_on = args.debug_mode_on
 
@@ -158,3 +157,5 @@ def predict_snp_effect_scores(rsids, ref_count_preds, alt_count_preds, ref_prob_
 
 
 
+if __name__=="__main__":
+    main()
diff --git a/chrombpnet/get_package_dir.py b/chrombpnet/get_package_dir.py
new file mode 100644
index 00000000..13c485c9
--- /dev/null
+++ b/chrombpnet/get_package_dir.py
@@ -0,0 +1,4 @@
+import os
+
+def main():
+    print(os.path.dirname(__file__))
\ No newline at end of file
diff --git a/chrombpnet/helpers/__init__.py b/chrombpnet/helpers/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/chrombpnet/helpers/data_generator_examples/README.md b/chrombpnet/helpers/data_generator_examples/README.md
new file mode 100644
index 00000000..e69de29b
diff --git a/src/helpers/data_generator_examples/batchgen_generator_example.ipynb b/chrombpnet/helpers/data_generator_examples/batchgen_generator_example.ipynb
similarity index 100%
rename from src/helpers/data_generator_examples/batchgen_generator_example.ipynb
rename to chrombpnet/helpers/data_generator_examples/batchgen_generator_example.ipynb
diff --git a/chrombpnet/helpers/hyperparameters/README.md b/chrombpnet/helpers/hyperparameters/README.md
new file mode 100644
index 00000000..e69de29b
diff --git a/chrombpnet/helpers/hyperparameters/__init__.py b/chrombpnet/helpers/hyperparameters/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/src/helpers/hyperparameters/find_bias_hyperparams.py b/chrombpnet/helpers/hyperparameters/find_bias_hyperparams.py
similarity index 94%
rename from src/helpers/hyperparameters/find_bias_hyperparams.py
rename to chrombpnet/helpers/hyperparameters/find_bias_hyperparams.py
index 7d92d100..a1968cf8 100644
--- a/src/helpers/hyperparameters/find_bias_hyperparams.py
+++ b/chrombpnet/helpers/hyperparameters/find_bias_hyperparams.py
@@ -5,7 +5,7 @@
 import numpy as np
 import os
 import json
-import param_utils
+import chrombpnet.helpers.hyperparameters.param_utils as param_utils
 
 def parse_data_args():
     parser=argparse.ArgumentParser(description="find hyper-parameters for chrombpnet defined in src/training/models/chrombpnet_with_bias_model.py")
@@ -29,8 +29,7 @@ def parse_model_args(parser):
     args = parser.parse_args()
     return args
 
-if __name__=="__main__":
-
+def main():    
     # read the arguments
     parser = parse_data_args()
     args = parse_model_args(parser)
@@ -69,14 +68,14 @@ def parse_model_args(parser):
     test_nonpeaks = in_nonpeaks[(in_nonpeaks["chr"].isin(test_chroms_to_keep))]
 
     # step 1 filtering: filter nonpeaks that are in the edges - prevents us from making the inputlen regions - do this for all train/test/valid   
-    nonpeaks = param_utils.filter_edge_regions(nonpeaks, bw, args.inputlen+2*args.max_jitter, peaks_bool=0)
+    nonpeaks = param_utils.filter_edge_regions(nonpeaks, bw, args.inputlen, peaks_bool=0)
     test_nonpeaks = param_utils.filter_edge_regions(test_nonpeaks, bw, args.inputlen, peaks_bool=0)
 
     peaks = param_utils.filter_edge_regions(peaks, bw, args.inputlen, peaks_bool=1)
 
     # step 2 filtering: filter nonpeaks that have counts less than a threshold_factor (minimum of peak counts)
-    peak_cnts, peak_seqs = param_utils.get_seqs_cts(genome, bw, peaks, args.inputlen, args.outputlen)
-    nonpeak_cnts, nonpeak_seqs = param_utils.get_seqs_cts(genome, bw, nonpeaks, args.inputlen, args.outputlen)    
+    peak_cnts, _ = param_utils.get_seqs_cts(genome, bw, peaks, args.inputlen, args.outputlen)
+    nonpeak_cnts, _ = param_utils.get_seqs_cts(genome, bw, nonpeaks, args.inputlen, args.outputlen)    
     assert(len(peak_cnts) == peaks.shape[0])
     assert(len(nonpeak_cnts) == nonpeaks.shape[0])
 
@@ -135,3 +134,7 @@ def parse_model_args(parser):
     file.write("\n")
     file.write("\t".join(["negative_sampling_ratio", str(1.0)])) # this is just a dummy variable because the train.py pipeline needs it - all negatives will be used for bias model training
     file.close()
+
+
+if __name__=="__main__":
+    main()
diff --git a/src/helpers/hyperparameters/find_chrombpnet_hyperparams.py b/chrombpnet/helpers/hyperparameters/find_chrombpnet_hyperparams.py
similarity index 95%
rename from src/helpers/hyperparameters/find_chrombpnet_hyperparams.py
rename to chrombpnet/helpers/hyperparameters/find_chrombpnet_hyperparams.py
index c94a8b2a..0b9d40de 100644
--- a/src/helpers/hyperparameters/find_chrombpnet_hyperparams.py
+++ b/chrombpnet/helpers/hyperparameters/find_chrombpnet_hyperparams.py
@@ -4,8 +4,7 @@
 import pandas as pd
 import numpy as np
 import os
-import param_utils
-from context import load_model_wrapper
+from chrombpnet.helpers.hyperparameters import param_utils as param_utils
 from tensorflow import keras
 import json
 
@@ -58,8 +57,8 @@ def adjust_bias_model_logcounts(bias_model, seqs, cts):
     bias_model.layers[-1].set_weights([dw, db+delta])
     return bias_model
 
-if __name__=="__main__":
 
+def main(): 
     # read the arguments
     parser = parse_data_args()
     args = parse_model_args(parser)
@@ -100,11 +99,11 @@ def adjust_bias_model_logcounts(bias_model, seqs, cts):
     peaks = param_utils.filter_edge_regions(peaks, bw, args.inputlen+2*args.max_jitter, peaks_bool=1)
     test_peaks = param_utils.filter_edge_regions(test_peaks, bw, args.inputlen, peaks_bool=1)
    
-    nonpeaks = param_utils.filter_edge_regions(nonpeaks, bw, args.inputlen+2*args.max_jitter, peaks_bool=0)
+    nonpeaks = param_utils.filter_edge_regions(nonpeaks, bw, args.inputlen, peaks_bool=0)
     test_nonpeaks = param_utils.filter_edge_regions(test_nonpeaks, bw, args.inputlen, peaks_bool=0)
 
     # step 2 filtering: filter peaks that are outliers in train and valid set - no filtering on test set
-    peak_cnts, peak_seqs = param_utils.get_seqs_cts(genome, bw, peaks, args.inputlen, args.outputlen)
+    peak_cnts, _ = param_utils.get_seqs_cts(genome, bw, peaks, args.inputlen, args.outputlen)
     nonpeak_cnts, nonpeak_seqs = param_utils.get_seqs_cts(genome, bw, nonpeaks, args.inputlen, args.outputlen)    
     assert(len(peak_cnts) == peaks.shape[0])
     assert(len(nonpeak_cnts) == nonpeaks.shape[0])
@@ -145,7 +144,7 @@ def adjust_bias_model_logcounts(bias_model, seqs, cts):
 
     # adjust bias model for training  - using train and validation set
     # the bias model might be trained on a difference read depth compared to the given data - so this step scales the bias model to account for that
-    bias_model = load_model_wrapper(args.bias_model_path)
+    bias_model = param_utils.load_model_wrapper(args.bias_model_path)
     bias_model_scaled = adjust_bias_model_logcounts(bias_model, nonpeak_seqs[(nonpeak_cnts< upper_thresh) & (nonpeak_cnts>lower_thresh)], nonpeak_cnts[(nonpeak_cnts< upper_thresh) & (nonpeak_cnts>lower_thresh)])
     # save the new bias model
     bias_model_scaled.save(os.path.join(args.output_dir, "bias_model_scaled.h5"))
@@ -179,3 +178,7 @@ def adjust_bias_model_logcounts(bias_model, seqs, cts):
     file.write("\n")
     file.write("\t".join(["negative_sampling_ratio", str(args.negative_sampling_ratio)]))
     file.close()
+
+if __name__=="__main__":
+    main()
+    
diff --git a/src/helpers/hyperparameters/param_utils.py b/chrombpnet/helpers/hyperparameters/param_utils.py
similarity index 74%
rename from src/helpers/hyperparameters/param_utils.py
rename to chrombpnet/helpers/hyperparameters/param_utils.py
index 25357aaf..c0ebf418 100644
--- a/src/helpers/hyperparameters/param_utils.py
+++ b/chrombpnet/helpers/hyperparameters/param_utils.py
@@ -1,5 +1,9 @@
 import numpy as np
-from context import one_hot
+import chrombpnet.training.utils.one_hot as one_hot
+import tensorflow as tf
+from tensorflow.keras.utils import get_custom_objects
+from tensorflow.keras.models import load_model
+import chrombpnet.training.utils.losses as losses
 
 def filter_edge_regions(peaks_df, bw, width, peaks_bool):
     """
@@ -17,7 +21,7 @@ def filter_edge_regions(peaks_df, bw, width, peaks_bool):
     chrom_to_sizes = bw.chroms()
     filtered = []
     for i, r in peaks_df.iterrows():
-        if r['start'] + r['summit'] + width//2 > chrom_to_sizes[r['chr']] :
+        if r['start'] + r['summit'] + width//2 > chrom_to_sizes.get(r['chr'], 0) :
             filtered.append(True)
         else:
             filtered.append(False)
@@ -50,3 +54,14 @@ def get_seqs_cts(genome, bw, peaks_df, input_width=2114, output_width=1000):
                             (r['start'] + r['summit']) + output_width//2))
         vals.append(bigwig_vals)
     return (np.sum(np.array(vals),axis=1), one_hot.dna_to_one_hot(seqs))
+
+def load_model_wrapper(model_h5):
+    # read .h5 model
+    custom_objects={"tf": tf, "multinomial_nll":losses.multinomial_nll}    
+    get_custom_objects().update(custom_objects)    
+    model=load_model(model_h5)
+    print("got the model")
+    model.summary()
+    return model
+
+
diff --git a/chrombpnet/helpers/make_chr_splits/__init__.py b/chrombpnet/helpers/make_chr_splits/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/chrombpnet/helpers/make_chr_splits/splits.py b/chrombpnet/helpers/make_chr_splits/splits.py
new file mode 100644
index 00000000..8978da0f
--- /dev/null
+++ b/chrombpnet/helpers/make_chr_splits/splits.py
@@ -0,0 +1,44 @@
+import json
+import argparse
+import os
+
+def main(): 
+    parser = argparse.ArgumentParser()
+    parser.add_argument("-o", "--output_dir", type=str, required=True, help="Path to store the fold information")
+    args = parser.parse_args()
+
+    # mention what the outputformat should look like for further editing
+
+    chroms = ['chr1','chr2','chr3','chr4','chr5','chr6','chr7','chr8', 'chr9','chr10', 'chr11','chr12','chr13','chr14','chr15','chr16','chr17','chr18','chr19','chr20','chr21','chr22','chrX','chrY']
+    splits=dict()
+
+    splits[0]={'test':['chr1', 'chr3', 'chr6'],
+               'valid':['chr8', 'chr20']}
+    splits[0]['train'] = [chrom for chrom in chroms if chrom not in splits[0]['test']+splits[0]['valid']]
+    json.dump(splits[0], open(os.path.join(args.output_dir, "fold_0.json"),"w"), indent=4)
+
+    splits[1]={'test':['chr2', 'chr8', 'chr9', 'chr16'],
+               'valid':[ 'chr12', 'chr17']}
+    splits[1]['train'] = [chrom for chrom in chroms if chrom not in splits[1]['test']+splits[1]['valid']]
+    json.dump(splits[1], open(os.path.join(args.output_dir, "fold_1.json"),"w"), indent=4)
+
+    splits[2]={'test':['chr4','chr11', 'chr12', 'chr15', 'chrY'],
+               'valid':['chr22','chr7']}
+    splits[2]['train'] = [chrom for chrom in chroms if chrom not in splits[2]['test']+splits[2]['valid']]
+    json.dump(splits[2], open(os.path.join(args.output_dir, "fold_2.json"),"w"), indent=4)
+
+
+    splits[3]={'test':['chr5','chr10','chr14', 'chr18', 'chr20', 'chr22'],
+               'valid':['chr6', 'chr21']}
+    splits[3]['train'] = [chrom for chrom in chroms if chrom not in splits[3]['test']+splits[3]['valid']]
+    json.dump(splits[3], open(os.path.join(args.output_dir, "fold_3.json"),"w"), indent=4)
+
+
+    splits[4]={'test':['chr7','chr13','chr17', 'chr19', 'chr21', 'chrX'],
+               'valid':['chr10','chr18']}
+    splits[4]['train'] = [chrom for chrom in chroms if chrom not in splits[4]['test']+splits[4]['valid']]
+    json.dump(splits[4], open(os.path.join(args.output_dir, "fold_4.json"),"w"), indent=4)
+
+if __name__=="__main__":
+    main()
+    
diff --git a/src/helpers/make_gc_matched_negatives/README.md b/chrombpnet/helpers/make_gc_matched_negatives/README.md
similarity index 56%
rename from src/helpers/make_gc_matched_negatives/README.md
rename to chrombpnet/helpers/make_gc_matched_negatives/README.md
index 0edb3ee1..6ed6b859 100644
--- a/src/helpers/make_gc_matched_negatives/README.md
+++ b/chrombpnet/helpers/make_gc_matched_negatives/README.md
@@ -3,12 +3,11 @@ Scripts to get  non-peak regions gc-matched with a given foreground (or peak) se
 ### Usage
 
 ```bash 
-bash  run.sh [foreground_bed] [exclude_bed] [inputlen] [output_dir] [genome] [genomewide_gc] [fold] [chrom_sizes]
+chmod +x make_gc_matched_negatives.sh
+./make_gc_matched_negatives.sh [foreground_bed] [exclude_bed] [inputlen] [output_dir] [genome] [genomewide_gc] [fold] [chrom_sizes]
 ```
 
-The above script runs two python scripts `get_gc_content.py` and `get_gc_matched_negatives.py` and a `bedtools` operation. Briefly `get_gc_content.py` finds the gc content distribution of the given foreground regions. This script filters the foreground regions if `inputlen` region cannot be formed (if the percentage of peaks filtered is high consider reducing the `inputlen` as your genome might be small). The bedtools operation keeps only those genomewide bins that do not fall in exclude bed as candidate negatives for gc-matching. `get_gc_matched_negatives.py` filters the candidate negatives list to as many negative regions as foreround regions such that they are gc-mactched with foreground.
-
-NOTE: Here I assume the script `run.sh` is executed from the main chrombpnet_paper repo - if you want to run these scripts while in this directory modify the paths in `run.sh`
+The above script runs two python scripts `get_gc_content.py` (also called with the command `chrombpnet_gc_content_foreground`) and `get_gc_matched_negatives.py` (also called with the command `chrombpnet_gc_matched_negatives`) and a `bedtools` operation. Briefly `get_gc_content.py` finds the gc content distribution of the given foreground regions. This script filters the foreground regions if `inputlen` region cannot be formed (if the percentage of peaks filtered is high consider reducing the `inputlen` as your genome might be small). The bedtools operation keeps only those genomewide bins that do not fall in exclude bed as candidate negatives for gc-matching. `get_gc_matched_negatives.py`  filters the candidate negatives list to as many negative regions as foreround regions such that they are gc-mactched with foreground.
 
 ### Input format:
 
@@ -17,7 +16,7 @@ NOTE: Here I assume the script `run.sh` is executed from the main chrombpnet_pap
 - inputlen: The input length to consider for foreground gc-fraction calculation.
 - output_dir: Directory to store the output files. Make sure the directory already exists. The code generates three output files described below in output format section.
 - genome: Reference geneome fasta.
-- genomewide_gc: Must be TSV file containing chr, start, end and gc_content. These are genome wide regions binned into `inputlen` regions and with a given stride. This pickle file can be generated using the scripts at `get_genomewide_gc_buckets/run.sh`. If you are using hg38 human reference genome and are (1) using a  `inputlen` of 2114 you can use the pre-generated pickle file saved on the cluster `/oak/stanford/groups/akundaje/anusri/refs/genomewide_gc_hg38_stride_50_inputlen_1057.bed` OR (2) if you are using a `inputlen` of 1000 you can use the pre-generated pickle file saved on the cluster `/oak/stanford/groups/akundaje/anusri/refs/genomewide_gc_hg38_stride_50_inputlen_1057.bed`
+- genomewide_gc: Must be TSV file containing chr, start, end and gc_content. These are genome wide regions binned into `inputlen` regions and with a given stride. This pickle file can be generated using the scripts at `get_genomewide_gc_buckets/make_gc_matched_negatives.sh`. If you are using hg38 human reference genome and are (1) using a  `inputlen` of 2114 you can use the pre-generated pickle file saved on the cluster `/oak/stanford/groups/akundaje/anusri/refs/genomewide_gc_hg38_stride_50_inputlen_1057.bed` OR (2) if you are using a `inputlen` of 1000 you can use the pre-generated pickle file saved on the cluster `/oak/stanford/groups/akundaje/anusri/refs/genomewide_gc_hg38_stride_50_inputlen_1057.bed`
 - fold: A json file containing a dictionary with test,valid and train keys and values with corresponding chromosomes.
 - chrom_sizes: TSV file with chromosome name in first column and size in the second column.
 
diff --git a/chrombpnet/helpers/make_gc_matched_negatives/__init__.py b/chrombpnet/helpers/make_gc_matched_negatives/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/src/helpers/make_gc_matched_negatives/get_gc_content.py b/chrombpnet/helpers/make_gc_matched_negatives/get_gc_content.py
similarity index 100%
rename from src/helpers/make_gc_matched_negatives/get_gc_content.py
rename to chrombpnet/helpers/make_gc_matched_negatives/get_gc_content.py
diff --git a/src/helpers/make_gc_matched_negatives/get_gc_matched_negatives.py b/chrombpnet/helpers/make_gc_matched_negatives/get_gc_matched_negatives.py
old mode 100644
new mode 100755
similarity index 97%
rename from src/helpers/make_gc_matched_negatives/get_gc_matched_negatives.py
rename to chrombpnet/helpers/make_gc_matched_negatives/get_gc_matched_negatives.py
index 32f97894..898944cd
--- a/src/helpers/make_gc_matched_negatives/get_gc_matched_negatives.py
+++ b/chrombpnet/helpers/make_gc_matched_negatives/get_gc_matched_negatives.py
@@ -105,8 +105,7 @@ def adjust_gc(chrom,cur_gc,negatives,used_negatives):
 
         
     
-if __name__=="__main__":
-
+def main(): 
     args=parse_args()
 
     splits_dict=json.load(open(args.chr_fold_path))
@@ -172,3 +171,5 @@ def adjust_gc(chrom,cur_gc,negatives,used_negatives):
     plt.savefig(args.output_prefix+"_compared_with_foreground.png")
 
     
+if __name__=="__main__":
+    main()
diff --git a/src/helpers/make_gc_matched_negatives/get_genomewide_gc_buckets/README.md b/chrombpnet/helpers/make_gc_matched_negatives/get_genomewide_gc_buckets/README.md
similarity index 84%
rename from src/helpers/make_gc_matched_negatives/get_genomewide_gc_buckets/README.md
rename to chrombpnet/helpers/make_gc_matched_negatives/get_genomewide_gc_buckets/README.md
index 60f7dc3d..f0ba7c18 100644
--- a/src/helpers/make_gc_matched_negatives/get_genomewide_gc_buckets/README.md
+++ b/chrombpnet/helpers/make_gc_matched_negatives/get_genomewide_gc_buckets/README.md
@@ -2,8 +2,8 @@ Scripts to find the gc content of genome wide bins.
 
 ### Usage
 
-```bash 
-python get_genomewide_gc_bins.py -g [genome] -o [output_prefix]  -f [inputlen] -s [stride]
+```
+chrombpnet_genomewide_gc -g [genome] -o [output_prefix]  -f [inputlen] -s [stride]
 ```
 
 The above scripts bins the genome into `inputlen` length regions. The bin intervals are spaced at `stride` length.
@@ -25,5 +25,5 @@ at  http://mitra.stanford.edu/kundaje/anusri/chrombpnet_downloads/genomewide_gc_
 ```
 wget https://www.encodeproject.org/files/GRCh38_no_alt_analysis_set_GCA_000001405.15/@@download/GRCh38_no_alt_analysis_set_GCA_000001405.15.fasta.gz
 gzip -d GRCh38_no_alt_analysis_set_GCA_000001405.15.fasta.gz
-python get_genomewide_gc_bins.py -g GRCh38_no_alt_analysis_set_GCA_000001405.15.fasta -o genomewide_gc_hg38_stride_1000_inputlen_2114 -f 2114 -s 1000
+chrombpnet_genomewide_gc -g GRCh38_no_alt_analysis_set_GCA_000001405.15.fasta -o genomewide_gc_hg38_stride_1000_inputlen_2114 -f 2114 -s 1000
 ```
diff --git a/chrombpnet/helpers/make_gc_matched_negatives/get_genomewide_gc_buckets/__init__.py b/chrombpnet/helpers/make_gc_matched_negatives/get_genomewide_gc_buckets/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/src/helpers/make_gc_matched_negatives/get_genomewide_gc_buckets/get_genomewide_gc_bins.py b/chrombpnet/helpers/make_gc_matched_negatives/get_genomewide_gc_buckets/get_genomewide_gc_bins.py
similarity index 98%
rename from src/helpers/make_gc_matched_negatives/get_genomewide_gc_buckets/get_genomewide_gc_bins.py
rename to chrombpnet/helpers/make_gc_matched_negatives/get_genomewide_gc_buckets/get_genomewide_gc_bins.py
index 721c8a19..40136c9d 100644
--- a/src/helpers/make_gc_matched_negatives/get_genomewide_gc_buckets/get_genomewide_gc_bins.py
+++ b/chrombpnet/helpers/make_gc_matched_negatives/get_genomewide_gc_buckets/get_genomewide_gc_bins.py
@@ -68,7 +68,11 @@ def get_genomewide_gc(genome_fa, outf, width, stride):
 
     f.close()
     outf.close()
-
-if __name__=="__main__":
+    
+def main():
     args = parse_args()
     get_genomewide_gc(args.genome, args.output_prefix+".bed", args.inputlen, args.stride)
+
+    
+if __name__=="__main__":
+    main()
diff --git a/src/helpers/make_gc_matched_negatives/run.sh b/chrombpnet/helpers/make_gc_matched_negatives/make_gc_matched_negatives.sh
similarity index 62%
rename from src/helpers/make_gc_matched_negatives/run.sh
rename to chrombpnet/helpers/make_gc_matched_negatives/make_gc_matched_negatives.sh
index e78a2cc9..f151a825 100755
--- a/src/helpers/make_gc_matched_negatives/run.sh
+++ b/chrombpnet/helpers/make_gc_matched_negatives/make_gc_matched_negatives.sh
@@ -7,15 +7,15 @@ trap 'last_command=$current_command; current_command=$BASH_COMMAND' DEBUG
 # echo an error message before exiting
 trap 'echo "\"${last_command}\" command filed with exit code $?."' EXIT
 
-foreground_bed=$1
-exclude_bed=$2
-inputlen=$3
-output_dir=$4
-genome=$5
-genomewide_gc=$6
-fold=$7
-chrom_sizes=$8
-logfile=$9
+foreground_bed=${1?param missing - foreground_bed}
+exclude_bed=${2?param missing - exclude_bed}
+inputlen=${3?param missing - inputlen}
+output_dir=${4?param missing - output_dir}
+genome=${5?param missing - genome}
+genomewide_gc=${6?param missing - genomewide_gc}
+fold=${7?param missing - fold}
+chrom_sizes=${8?param missing - chrom_sizes}
+logfile=${9}
 
 function timestamp {
     # Function to get the current time with the new line character
@@ -34,36 +34,36 @@ if [ -z "$logfile" ]
 fi
 
 echo $( timestamp ): "get gc content of the positive sequences" | tee -a $logfile
-echo $( timestamp ): "python $PWD/src/helpers/make_gc_matched_negatives/get_gc_content.py \\
+echo $( timestamp ): "chrombpnet_gc_content_foreground \\
         --input_bed $foreground_bed \\
         --genome $genome \\
         --chrom_sizes $chrom_sizes \\
         --output_prefix $output_dir/foreground.gc \\
         --inputlen $inputlen" | tee -a $logfile
 
-python $PWD/src/helpers/make_gc_matched_negatives/get_gc_content.py \
-        --input_bed $foreground_bed \
-        --genome $genome \
-        --chrom_sizes $chrom_sizes \
-        --output_prefix $output_dir/foreground.gc \
-        --inputlen $inputlen | tee -a $logfile
+chrombpnet_gc_content_foreground \
+       --input_bed $foreground_bed \
+       --genome $genome \
+       --chrom_sizes $chrom_sizes \
+       --output_prefix $output_dir/foreground.gc \
+       --inputlen $inputlen | tee -a $logfile
 
 echo $( timestamp ): "get candidate negative bed" | tee -a $logfile
 echo $( timestamp ): "bedtools intersect -v -a $genomewide_gc -b $exclude_bed  > $output_dir/candidate.negatives.bed" | tee -a $logfile
 bedtools intersect -v -a $genomewide_gc -b $exclude_bed  > $output_dir/candidate.negatives.bed
 
 echo $( timestamp ): "find regions in candidate negative bed that gc-match wth foreground" | tee -a $logfile
-echo $( timestamp ): "python $PWD/src/helpers/make_gc_matched_negatives/get_gc_matched_negatives.py \\
+echo $( timestamp ): "chrombpnet_gc_matched_negatives \\
         --candidate_negatives $output_dir/candidate.negatives.bed \\
         --foreground_gc_bed $output_dir/foreground.gc.bed \\
         --output_prefix $output_dir/negatives \\
         --chr_fold_path $fold \\
         --neg_to_pos_ratio_train 2" | tee -a $logfile
-python $PWD/src/helpers/make_gc_matched_negatives/get_gc_matched_negatives.py \
-        --candidate_negatives $output_dir/candidate.negatives.bed \
-        --foreground_gc_bed $output_dir/foreground.gc.bed \
-        --output_prefix $output_dir/negatives \
-        --chr_fold_path $fold \
-        --neg_to_pos_ratio_train 2 | tee -a $logfile
+chrombpnet_gc_matched_negatives \
+    --candidate_negatives $output_dir/candidate.negatives.bed \
+    --foreground_gc_bed $output_dir/foreground.gc.bed \
+    --output_prefix $output_dir/negatives \
+    --chr_fold_path $fold \
+    --neg_to_pos_ratio_train 2 | tee -a $logfile
 
 
diff --git a/src/helpers/preprocessing/README.md b/chrombpnet/helpers/preprocessing/README.md
similarity index 94%
rename from src/helpers/preprocessing/README.md
rename to chrombpnet/helpers/preprocessing/README.md
index f4a1751f..4f34be15 100644
--- a/src/helpers/preprocessing/README.md
+++ b/chrombpnet/helpers/preprocessing/README.md
@@ -9,7 +9,7 @@ To run these scripts you will need the `samtools` and `bedGraphToBigWig` (from u
 ## Bam to Bigwig (+4/-4 shift for ATAC and 0/+1 shift for DNASE)
 
 ```
-bash bam_to_bigwig.sh [input_bam] [output_prefix] [data_type] [chrom_sizes]
+bam_to_bigwig.sh [input_bam] [output_prefix] [data_type] [chrom_sizes]
 ```
 
 The following assumptions are made with this script - make changes accordingly if the assumptions dont hold.
@@ -25,7 +25,7 @@ The following assumptions are made with this script - make changes accordingly i
 ## Example Usage
 
 ```
-bash bam_to_bigwig.sh input.bam <output_name> ATAC_PE hg38.chrom.sizes
+bam_to_bigwig.sh input.bam <output_name> ATAC_PE hg38.chrom.sizes
 <example output file> : <output_name>_unstranded.bw
 ```
 
diff --git a/chrombpnet/helpers/preprocessing/__init__.py b/chrombpnet/helpers/preprocessing/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/src/helpers/preprocessing/analysis/README.md b/chrombpnet/helpers/preprocessing/analysis/README.md
similarity index 100%
rename from src/helpers/preprocessing/analysis/README.md
rename to chrombpnet/helpers/preprocessing/analysis/README.md
diff --git a/chrombpnet/helpers/preprocessing/analysis/__init__.py b/chrombpnet/helpers/preprocessing/analysis/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/src/helpers/preprocessing/analysis/build_pwm_from_bigwig.py b/chrombpnet/helpers/preprocessing/analysis/build_pwm_from_bigwig.py
similarity index 97%
rename from src/helpers/preprocessing/analysis/build_pwm_from_bigwig.py
rename to chrombpnet/helpers/preprocessing/analysis/build_pwm_from_bigwig.py
index 7bdd0982..774bf87b 100644
--- a/src/helpers/preprocessing/analysis/build_pwm_from_bigwig.py
+++ b/chrombpnet/helpers/preprocessing/analysis/build_pwm_from_bigwig.py
@@ -4,7 +4,7 @@
 from modisco.visualization import viz_sequence
 import matplotlib.pyplot as plt
 import argparse
-import one_hot
+import chrombpnet.training.utils.one_hot as one_hot
 
 def parse_args():
     parser=argparse.ArgumentParser(description="build pwm matrix from bigwig")
@@ -37,8 +37,7 @@ def get_pwm_bg(seqs, cnts, pwm_width=24):
     bg = bg/sum(bg)
     return motif, bg
 
-if __name__=="__main__":
-
+def main(): 
     args = parse_args()
 
     assert(args.pwm_width % 2 ==0)
@@ -67,3 +66,6 @@ def get_pwm_bg(seqs, cnts, pwm_width=24):
     ax = fig.add_subplot(111) 
     viz_sequence.plot_weights_given_ax(ax=ax, array=viz_sequence.ic_scale(motif, background=bg))
     plt.savefig(args.output_prefix+'.png')
+    
+if __name__=="__main__":
+    main()
diff --git a/src/helpers/preprocessing/bam_to_bigwig.sh b/chrombpnet/helpers/preprocessing/bam_to_bigwig.sh
similarity index 96%
rename from src/helpers/preprocessing/bam_to_bigwig.sh
rename to chrombpnet/helpers/preprocessing/bam_to_bigwig.sh
index ee3ccf5f..3cfaf6ee 100644
--- a/src/helpers/preprocessing/bam_to_bigwig.sh
+++ b/chrombpnet/helpers/preprocessing/bam_to_bigwig.sh
@@ -7,11 +7,11 @@ trap 'last_command=$current_command; current_command=$BASH_COMMAND' DEBUG
 # echo an error message before exiting
 trap 'echo "\"${last_command}\" command filed with exit code $?."' EXIT
 
-input_bam=$1
-output_prefix=$2
-data_type=$3
-chrom_sizes=$4
-logfile=$5
+input_bam=${1?param missing - input_bam}
+output_prefix=${2?param missing - output_prefix}
+data_type=${3?param missing - data_type} 
+chrom_sizes=${4?param missing - chrom_sizes}
+logfile=${5}
 
 function timestamp {
     # Function to get the current time with the new line character
diff --git a/src/helpers/preprocessing/images/atac_44_shift.png b/chrombpnet/helpers/preprocessing/images/atac_44_shift.png
similarity index 100%
rename from src/helpers/preprocessing/images/atac_44_shift.png
rename to chrombpnet/helpers/preprocessing/images/atac_44_shift.png
diff --git a/src/helpers/preprocessing/images/atac_45_shift.png b/chrombpnet/helpers/preprocessing/images/atac_45_shift.png
similarity index 100%
rename from src/helpers/preprocessing/images/atac_45_shift.png
rename to chrombpnet/helpers/preprocessing/images/atac_45_shift.png
diff --git a/src/helpers/preprocessing/images/atac_no_shift.png b/chrombpnet/helpers/preprocessing/images/atac_no_shift.png
similarity index 100%
rename from src/helpers/preprocessing/images/atac_no_shift.png
rename to chrombpnet/helpers/preprocessing/images/atac_no_shift.png
diff --git a/src/helpers/preprocessing/images/dnase_01_shift.png b/chrombpnet/helpers/preprocessing/images/dnase_01_shift.png
similarity index 100%
rename from src/helpers/preprocessing/images/dnase_01_shift.png
rename to chrombpnet/helpers/preprocessing/images/dnase_01_shift.png
diff --git a/src/helpers/preprocessing/images/dnase_no_shift.png b/chrombpnet/helpers/preprocessing/images/dnase_no_shift.png
similarity index 100%
rename from src/helpers/preprocessing/images/dnase_no_shift.png
rename to chrombpnet/helpers/preprocessing/images/dnase_no_shift.png
diff --git a/src/helpers/preprocessing/images/script.sh b/chrombpnet/helpers/preprocessing/images/script.sh
similarity index 100%
rename from src/helpers/preprocessing/images/script.sh
rename to chrombpnet/helpers/preprocessing/images/script.sh
diff --git a/chrombpnet/training/__init__.py b/chrombpnet/training/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/chrombpnet/training/data_generators/README.md b/chrombpnet/training/data_generators/README.md
new file mode 100644
index 00000000..e69de29b
diff --git a/chrombpnet/training/data_generators/__init__.py b/chrombpnet/training/data_generators/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/src/training/data_generators/batchgen_generator.py b/chrombpnet/training/data_generators/batchgen_generator.py
similarity index 77%
rename from src/training/data_generators/batchgen_generator.py
rename to chrombpnet/training/data_generators/batchgen_generator.py
index ebd91906..f5111079 100644
--- a/src/training/data_generators/batchgen_generator.py
+++ b/chrombpnet/training/data_generators/batchgen_generator.py
@@ -1,6 +1,6 @@
 from tensorflow import keras
-from utils import augment
-from utils import data_utils
+from chrombpnet.training.utils import augment
+from chrombpnet.training.utils import data_utils
 import tensorflow as tf
 import numpy as np
 import random
@@ -60,20 +60,31 @@ def crop_revcomp_data(self):
         # shuffle required since otherwise peaks and nonpeaks will be together
         #Sample a fraction of the negative samples according to the specified ratio
         if (self.peak_seqs is not None) and (self.nonpeak_seqs is not None):
+            # crop peak data before stacking
+            cropped_peaks, cropped_cnts, cropped_coords = augment.random_crop(self.peak_seqs, self.peak_cts, self.inputlen, self.outputlen, self.peak_coords)
+            #print(cropped_peaks.shape)
+            #print(self.nonpeak_seqs.shape)
             if self.negative_sampling_ratio < 1.0:
                 self.sampled_nonpeak_seqs, self.sampled_nonpeak_cts, self.sampled_nonpeak_coords = subsample_nonpeak_data(self.nonpeak_seqs, self.nonpeak_cts, self.nonpeak_coords, len(self.peak_seqs), self.negative_sampling_ratio)
-                self.seqs = np.vstack([self.peak_seqs, self.sampled_nonpeak_seqs])
-                self.cts = np.vstack([self.peak_cts, self.sampled_nonpeak_cts])
-                self.coords = np.vstack([self.peak_coords, self.sampled_nonpeak_coords])
+                self.seqs = np.vstack([cropped_peaks, self.sampled_nonpeak_seqs])
+                self.cts = np.vstack([cropped_cnts, self.sampled_nonpeak_cts])
+                self.coords = np.vstack([cropped_coords, self.sampled_nonpeak_coords])
             else:
-                self.seqs = np.vstack([self.peak_seqs, self.nonpeak_seqs])
-                self.cts = np.vstack([self.peak_cts, self.nonpeak_cts])
-                self.coords = np.vstack([self.peak_coords, self.nonpeak_coords])
+                self.seqs = np.vstack([cropped_peaks, self.nonpeak_seqs])
+                self.cts = np.vstack([cropped_cnts, self.nonpeak_cts])
+                self.coords = np.vstack([cropped_coords, self.nonpeak_coords])
+
         elif self.peak_seqs is not None:
-            self.seqs = self.peak_seqs
-            self.cts = self.peak_cts
-            self.coords = self.peak_coords
+            # crop peak data before stacking
+            cropped_peaks, cropped_cnts, cropped_coords = augment.random_crop(self.peak_seqs, self.peak_cts, self.inputlen, self.outputlen, self.peak_coords)
+
+            self.seqs = cropped_peaks
+            self.cts = cropped_cnts
+            self.coords = cropped_coords
+
         elif self.nonpeak_seqs is not None:
+            #print(self.nonpeak_seqs.shape)
+
             self.seqs = self.nonpeak_seqs
             self.cts = self.nonpeak_cts
             self.coords = self.nonpeak_coords
diff --git a/src/training/data_generators/initializers.py b/chrombpnet/training/data_generators/initializers.py
similarity index 94%
rename from src/training/data_generators/initializers.py
rename to chrombpnet/training/data_generators/initializers.py
index daf108e7..f074fd30 100644
--- a/src/training/data_generators/initializers.py
+++ b/chrombpnet/training/data_generators/initializers.py
@@ -1,5 +1,5 @@
-import data_generators.batchgen_generator as batchgen_generator
-from utils import data_utils
+import chrombpnet.training.data_generators.batchgen_generator as batchgen_generator
+from chrombpnet.training.utils import data_utils
 import pandas as pd
 import json
 
diff --git a/src/training/metrics.py b/chrombpnet/training/metrics.py
similarity index 96%
rename from src/training/metrics.py
rename to chrombpnet/training/metrics.py
index 61ef40a9..2a5b1141 100644
--- a/src/training/metrics.py
+++ b/chrombpnet/training/metrics.py
@@ -8,7 +8,7 @@
 from matplotlib import cm
 from matplotlib.colors import Normalize 
 from scipy.interpolate import interpn
-from utils.metrics_utils import * 
+from chrombpnet.training.utils.metrics_utils import * 
 
 plt.rcParams["figure.figsize"]=10,5
 font = {'family' : 'normal',
diff --git a/chrombpnet/training/models/__init__.py b/chrombpnet/training/models/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/src/training/models/bpnet_model.py b/chrombpnet/training/models/bpnet_model.py
similarity index 96%
rename from src/training/models/bpnet_model.py
rename to chrombpnet/training/models/bpnet_model.py
index d37d22d6..39e29df7 100644
--- a/src/training/models/bpnet_model.py
+++ b/chrombpnet/training/models/bpnet_model.py
@@ -3,7 +3,7 @@
 from tensorflow.keras.layers import Input, Cropping1D, add, Conv1D, GlobalAvgPool1D, Dense, Flatten
 from tensorflow.keras.optimizers import Adam
 from tensorflow.keras.models import Model
-from utils.losses import multinomial_nll
+from chrombpnet.training.utils.losses import multinomial_nll
 import tensorflow as tf
 import random as rn
 import os 
@@ -73,7 +73,7 @@ def getModelGivenModelOptionsAndWeightInits(args, model_params):
     # Step 1.2 - Crop to match size of the required output size
     cropsize = int(int_shape(prof_out_precrop)[1]/2)-int(out_pred_len/2)
     assert cropsize>=0
-    assert (cropsize % 2 == 0) # Necessary for symmetric cropping
+    assert (int_shape(prof_out_precrop)[1] % 2 == 0) # Necessary for symmetric cropping
     prof = Cropping1D(cropsize,
                 name='logits_profile_predictions_preflatten')(prof_out_precrop)
 
diff --git a/src/training/models/chrombpnet_with_bias_model.py b/chrombpnet/training/models/chrombpnet_with_bias_model.py
similarity index 95%
rename from src/training/models/chrombpnet_with_bias_model.py
rename to chrombpnet/training/models/chrombpnet_with_bias_model.py
index 29465306..de11d283 100644
--- a/src/training/models/chrombpnet_with_bias_model.py
+++ b/chrombpnet/training/models/chrombpnet_with_bias_model.py
@@ -3,7 +3,7 @@
 from tensorflow.keras.layers import Input, Cropping1D, add, Conv1D, GlobalAvgPool1D, Dense, Add, Concatenate, Lambda, Flatten
 from tensorflow.keras.optimizers import Adam
 from tensorflow.keras.models import Model
-from utils.losses import multinomial_nll
+from chrombpnet.training.utils.losses import multinomial_nll
 import tensorflow as tf
 import random as rn
 import os 
@@ -68,7 +68,7 @@ def bpnet_model(filters, n_dil_layers, sequence_len, out_pred_len):
     # Step 1.2 - Crop to match size of the required output size
     cropsize = int(int_shape(prof_out_precrop)[1]/2)-int(out_pred_len/2)
     assert cropsize>=0
-    assert (cropsize % 2 == 0) # Necessary for symmetric cropping
+    assert (int_shape(prof_out_precrop)[1] % 2 == 0) # Necessary for symmetric cropping
 
     prof = Cropping1D(cropsize,
                 name='wo_bias_bpnet_logitt_before_flatten')(prof_out_precrop)
diff --git a/src/training/predict.py b/chrombpnet/training/predict.py
similarity index 97%
rename from src/training/predict.py
rename to chrombpnet/training/predict.py
index e129f0fe..10468808 100644
--- a/src/training/predict.py
+++ b/chrombpnet/training/predict.py
@@ -1,17 +1,17 @@
-import utils.argmanager as argmanager
-import utils.losses as losses
-from tensorflow.keras.utils import get_custom_objects
-from tensorflow.keras.models import load_model
-from scipy import nanmean, nanstd
 import pandas as pd
 import os
 import scipy.stats
-import metrics
-import data_generators.initializers as initializers
 import numpy as np
 import json
 import h5py
 import tensorflow as tf
+import chrombpnet.training.utils.argmanager as argmanager
+import chrombpnet.training.utils.losses as losses
+import chrombpnet.training.metrics as metrics
+import chrombpnet.training.data_generators.initializers as initializers
+from tensorflow.keras.utils import get_custom_objects
+from tensorflow.keras.models import load_model
+from scipy import nanmean, nanstd
 
 def write_predictions_h5py(output_prefix, profile, logcts, coords):
     # open h5 file for writing predictions
diff --git a/src/training/train.py b/chrombpnet/training/train.py
similarity index 91%
rename from src/training/train.py
rename to chrombpnet/training/train.py
index c191bcda..49a28b90 100644
--- a/src/training/train.py
+++ b/chrombpnet/training/train.py
@@ -1,10 +1,10 @@
 from __future__ import division, print_function, absolute_import
 import importlib.machinery
 import tensorflow.keras.callbacks as tfcallbacks 
-import utils.argmanager as argmanager
-import utils.losses as losses
-import utils.callbacks as callbacks
-import data_generators.initializers as initializers
+import chrombpnet.training.utils.argmanager as argmanager
+import chrombpnet.training.utils.losses as losses
+import chrombpnet.training.utils.callbacks as callbacks
+import chrombpnet.training.data_generators.initializers as initializers
 import pandas as pd
 import os
 import json
@@ -33,8 +33,8 @@ def fit_and_evaluate(model,train_gen,valid_gen,args,architecture_module):
     earlystopper = tfcallbacks.EarlyStopping(monitor='val_loss', mode="min", patience=args.early_stop, verbose=1, restore_best_weights=True)
     history= callbacks.LossHistory(model_output_path_logs_name+".batch",args.trackables)
     csvlogger = tfcallbacks.CSVLogger(model_output_path_logs_name, append=False)
-    reduce_lr = tfcallbacks.ReduceLROnPlateau(monitor='val_loss',factor=0.4, patience=args.early_stop-2, min_lr=0.00000001)
-    cur_callbacks=[checkpointer,earlystopper,csvlogger,reduce_lr,history]
+    #reduce_lr = tfcallbacks.ReduceLROnPlateau(monitor='val_loss',factor=0.4, patience=args.early_stop-2, min_lr=0.00000001)
+    cur_callbacks=[checkpointer,earlystopper,csvlogger,history]
 
     model.fit(train_gen,
               validation_data=valid_gen,
diff --git a/chrombpnet/training/utils/__init__.py b/chrombpnet/training/utils/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/src/training/utils/argmanager.py b/chrombpnet/training/utils/argmanager.py
similarity index 100%
rename from src/training/utils/argmanager.py
rename to chrombpnet/training/utils/argmanager.py
diff --git a/src/training/utils/augment.py b/chrombpnet/training/utils/augment.py
similarity index 89%
rename from src/training/utils/augment.py
rename to chrombpnet/training/utils/augment.py
index 320a89c9..2d43c510 100644
--- a/src/training/utils/augment.py
+++ b/chrombpnet/training/utils/augment.py
@@ -29,9 +29,11 @@ def random_crop(seqs, labels, seq_crop_width, label_crop_width, coords):
     max_start = seqs.shape[1] - seq_crop_width # This should be the same for both input and output
 
     starts = np.random.choice(range(max_start+1), size=seqs.shape[0], replace=True)
-    coords[:,1] = coords[:,1].astype(int) + starts
 
-    return take_per_row(seqs, starts, seq_crop_width), take_per_row(labels, starts, label_crop_width), coords
+    new_coords = coords.copy()
+    new_coords[:,1] = new_coords[:,1].astype(int) - (seqs.shape[1]//2) + starts
+
+    return take_per_row(seqs, starts, seq_crop_width), take_per_row(labels, starts, label_crop_width), new_coords
 
 def random_rev_comp(seqs, labels, coords, frac=0.5):
     """
@@ -64,7 +66,8 @@ def crop_revcomp_augment(seqs, labels, coords, seq_crop_width, label_crop_width,
     assert(seqs.shape[0]==labels.shape[0])
 
     # this does not modify seqs and labels
-    mod_seqs, mod_labels, mod_coords = random_crop(seqs, labels, seq_crop_width, label_crop_width, coords)
+    #mod_seqs, mod_labels, mod_coords = random_crop(seqs, labels, seq_crop_width, label_crop_width, coords)
+    mod_seqs, mod_labels, mod_coords = seqs, labels, coords
 
     # this modifies mod_seqs, mod_labels in-place
     if add_revcomp:
diff --git a/src/training/utils/callbacks.py b/chrombpnet/training/utils/callbacks.py
similarity index 100%
rename from src/training/utils/callbacks.py
rename to chrombpnet/training/utils/callbacks.py
diff --git a/src/training/utils/data_utils.py b/chrombpnet/training/utils/data_utils.py
similarity index 95%
rename from src/training/utils/data_utils.py
rename to chrombpnet/training/utils/data_utils.py
index 3cc2eb42..261fd64e 100644
--- a/src/training/utils/data_utils.py
+++ b/chrombpnet/training/utils/data_utils.py
@@ -2,7 +2,7 @@
 import pandas as pd
 import pyBigWig
 import pyfaidx
-from utils import one_hot
+from chrombpnet.training.utils import one_hot
 
 
 def get_seq(peaks_df, genome, width):
@@ -87,8 +87,8 @@ def load_data(bed_regions, nonpeak_regions, genome_fasta, cts_bw_file, inputlen,
         train_nonpeaks_seqs, train_nonpeaks_cts, train_nonpeaks_coords = get_seq_cts_coords(nonpeak_regions,
                                               genome,
                                               cts_bw,
-                                              inputlen+2*max_jitter,
-                                              outputlen+2*max_jitter,
+                                              inputlen,
+                                              outputlen,
                                               peaks_bool=0)
 
 
@@ -97,4 +97,4 @@ def load_data(bed_regions, nonpeak_regions, genome_fasta, cts_bw_file, inputlen,
     genome.close()
 
     return (train_peaks_seqs, train_peaks_cts, train_peaks_coords,
-            train_nonpeaks_seqs, train_nonpeaks_cts, train_nonpeaks_coords)
\ No newline at end of file
+            train_nonpeaks_seqs, train_nonpeaks_cts, train_nonpeaks_coords)
diff --git a/src/training/utils/losses.py b/chrombpnet/training/utils/losses.py
similarity index 100%
rename from src/training/utils/losses.py
rename to chrombpnet/training/utils/losses.py
diff --git a/src/training/utils/metrics_utils.py b/chrombpnet/training/utils/metrics_utils.py
similarity index 100%
rename from src/training/utils/metrics_utils.py
rename to chrombpnet/training/utils/metrics_utils.py
diff --git a/src/evaluation/variant_effect_prediction/one_hot.py b/chrombpnet/training/utils/one_hot.py
similarity index 100%
rename from src/evaluation/variant_effect_prediction/one_hot.py
rename to chrombpnet/training/utils/one_hot.py
diff --git a/dockerfile b/dockerfile
index 9b83e2ea..6b30a32d 100755
--- a/dockerfile
+++ b/dockerfile
@@ -1,5 +1,5 @@
 # Use the official TensorFlow image as parent
-FROM tensorflow/tensorflow:2.4.1-gpu
+FROM tensorflow/tensorflow:2.8.2-gpu
 
 # Set the working directory
 WORKDIR /scratch
@@ -16,8 +16,8 @@ RUN cd /opt/ && \
     ./google-cloud-sdk/install.sh
 ENV PATH "$PATH:/opt/google-cloud-sdk/bin/"
 
-# Install Miniconda with Python 3.7 into /opt
-RUN wget --quiet https://repo.anaconda.com/miniconda/Miniconda3-py37_4.9.2-Linux-x86_64.sh -O ~/miniconda.sh && \
+# Install Miniconda with Python 3.9 into /opt
+RUN wget --quiet https://repo.anaconda.com/miniconda/Miniconda3-py39_4.12.0-Linux-x86_64.sh -O ~/miniconda.sh && \
     /bin/bash ~/miniconda.sh -b -p /opt/conda && \
     rm ~/miniconda.sh
 
@@ -37,7 +37,7 @@ RUN apt-get install -y jq
 
 # Clean up after apt and conda
 RUN apt-get clean && rm -rf /var/lib/apt/lists/*
-RUN conda clean -tipsy
+RUN conda clean -tipy
 
 # Set environment variables for Python
 ENV LC_ALL=C.UTF-8
diff --git a/requirements.txt b/requirements.txt
index e947b708..08015f7d 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,17 +1,18 @@
-h5py==2.10.0
-matplotlib==3.3.1
+h5py>=2.10.0
+matplotlib>=3.3.1
 matplotlib-venn==0.11.6
-numpy==1.19.5
-pandas==1.1.1 
+numpy>=1.20
+pandas>=1.3.4
 pyfaidx==0.6.1
-scikit-learn==0.23.2
-scipy==1.4.1
-tensorflow==2.4.1
-tensorflow-estimator==2.4.0
-tensorflow-probability==0.12.2 
+scikit-learn>=0.23.2
+scipy>=1.4.1
+tensorflow-gpu==2.8.0 
+tensorflow-estimator==2.8.0 
+tensorflow-probability==0.15.0
+protobuf==3.20
 tqdm==4.48.2
 pyBigWig==0.3.18
 deepdish==0.3.7
-git+https://github.com/AvantiShri/shap.git
+shap @ git+https://github.com/kundajelab/shap@master#egg=shap
 deeplift==0.6.13.0
 modisco==0.5.16.0
diff --git a/setup.py b/setup.py
new file mode 100755
index 00000000..f3f4349e
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,74 @@
+from setuptools import setup,find_packages
+from setuptools.command.develop import develop
+from setuptools.command.install import install
+
+class PostDevelopCommand(develop):
+    """Post-installation for development mode."""
+    def run(self):
+        develop.run(self)
+        print("WARNING: IF upgrading from v1.0 or v1.1 to v1.2, note that chrombpnet has undergone linting to generate a modular structure for release on pypi."
+        "Hard-coded script paths are no longer necessary. Please refer to the updated README to ensure your script calls are compatible with v1.2")
+
+class PostInstallCommand(install):
+    """Post-installation for installation mode."""
+    def run(self):
+        install.run(self)
+        print("WARNING: IF upgrading from v1.0 or v1.1 to v1.2, note that chrombpnet has undergone linting to generate a modular structure for release on pypi."
+        "Hard-coded script paths are no longer necessary. Please refer to the updated README to ensure your script calls are compatible with v1.2")
+
+#generate install_requires from requirements.txt file
+install_requires=open('requirements.txt','r').read().strip().split('\n')
+print(f"install_requires:{install_requires}")
+
+
+config = {
+    'name': 'chrombpnet',
+    'author': 'Kundaje lab',
+    'author_email': 'anusri @ stanford.edu',
+    'license': 'MIT',
+    'include_package_data': True,
+    'description': 'chrombpnet predicts chromatin accessibility from sequence',
+    'download_url': 'https://github.com/kundajelab/chrombpnet',
+    'version': '0.1',
+    'packages': find_packages(),
+    'python_requires': '>=3.8',
+    'install_requires': install_requires,
+    'zip_safe': False,
+    'scripts':['chrombpnet/helpers/make_gc_matched_negatives/make_gc_matched_negatives.sh',
+               'chrombpnet/helpers/preprocessing/bam_to_bigwig.sh',
+               'chrombpnet/training/models/bpnet_model.py',
+               'chrombpnet/training/models/chrombpnet_with_bias_model.py',
+               'chrombpnet/evaluation/modisco/modisco.sh',
+               'step1_download_bams_and_peaks.sh',
+               'step2_make_bigwigs_from_bams.sh',
+               'step3_get_background_regions.sh',
+               'step4_train_bias_model.sh',
+               'step5_interpret_bias_model.sh',
+               'step6_train_chrombpnet_model.sh',
+               'step7_interpret_chrombpnet_model.sh'
+    ],
+    'entry_points': {'console_scripts': [
+        'chrombpnet_genomewide_gc = chrombpnet.helpers.make_gc_matched_negatives.get_genomewide_gc_buckets.get_genomewide_gc_bins:main',
+        'chrombpnet_gc_content_foreground = chrombpnet.helpers.make_gc_matched_negatives.get_gc_content:main',
+        'chrombpnet_gc_matched_negatives = chrombpnet.helpers.make_gc_matched_negatives.get_gc_matched_negatives:main',
+        'chrombpnet_pwm_from_bigwig = chrombpnet.helpers.preprocessing.analysis.build_pwm_from_bigwig:main',        
+        'chrombpnet_make_splits = chrombpnet.helpers.make_chr_splits.splits:main',
+        'chrombpnet_hyperparams = chrombpnet.helpers.hyperparameters.find_chrombpnet_hyperparams:main',
+        'chrombpnet_bias_hyperparams = chrombpnet.helpers.hyperparameters.find_bias_hyperparams:main',
+        'chrombpnet_train = chrombpnet.training.train:main',
+        'chrombpnet_predict = chrombpnet.training.predict:main',
+        'chrombpnet_metrics = chrombpnet.training.metrics:main',
+        'chrombpnet_deepshap = chrombpnet.evaluation.interpret.interpret:main',
+        'chrombpnet_modisco = chrombpnet.evaluation.modisco.run_modisco:main',
+        'chrombpnet_marginal_footprints = chrombpnet.evaluation.marginal_footprints.marginal_footprinting:main',
+        'chrombpnet_tomtom_hits = chrombpnet.evaluation.modisco.fetch_tomtom:main',
+        'chrompnet_visualize_motif_matches = chrombpnet.evaluation.modisco.visualize_motif_matches:main',
+        'chrombpnet_score_snps = chrombpnet.evaluation.variant_effect_prediction.snp_scoring:main',
+        'chrombpnet_srcdir = chrombpnet.get_package_dir:main']},
+    'cmdclass':{ 'develop': PostDevelopCommand,
+                 'install': PostInstallCommand
+    }
+}
+
+if __name__== '__main__':
+    setup(**config)
diff --git a/src/evaluation/interpret/context.py b/src/evaluation/interpret/context.py
deleted file mode 100644
index a6f2e4a8..00000000
--- a/src/evaluation/interpret/context.py
+++ /dev/null
@@ -1,15 +0,0 @@
-import os
-import sys
-sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../../training/')))
-import utils.losses as losses
-from utils.data_utils import get_seq
-import tensorflow as tf
-
-def load_model_wrapper(args):
-    # read .h5 model
-    custom_objects={"multinomial_nll": losses.mutlinomial_nll, "tf": tf}    
-    get_custom_objects().update(custom_objects)    
-    model=load_model(args.model_h5)
-    print("got the model")
-    model.summary()
-    return model
diff --git a/src/evaluation/make_bigwigs/context.py b/src/evaluation/make_bigwigs/context.py
deleted file mode 100755
index 7523b2b4..00000000
--- a/src/evaluation/make_bigwigs/context.py
+++ /dev/null
@@ -1,19 +0,0 @@
-import os
-import sys
-sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../../training/')))
-import utils.losses as losses
-#from utils.data_utils import get_seq as get_seq
-import utils.data_utils as data_utils 
-import utils.one_hot as one_hot
-from tensorflow.keras.utils import get_custom_objects
-from tensorflow.keras.models import load_model
-import tensorflow as tf
-
-def load_model_wrapper(model_hdf5):
-    # read .h5 model
-    custom_objects={"multinomial_nll":losses.multinomial_nll, "tf": tf}    
-    get_custom_objects().update(custom_objects)    
-    model=load_model(model_hdf5)
-    print("got the model")
-    model.summary()
-    return model
diff --git a/src/evaluation/marginal_footprints/context.py b/src/evaluation/marginal_footprints/context.py
deleted file mode 100644
index 36127fe6..00000000
--- a/src/evaluation/marginal_footprints/context.py
+++ /dev/null
@@ -1,18 +0,0 @@
-import os
-import sys
-sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../../training/')))
-import utils.losses as losses
-from utils.data_utils import get_seq as get_seq
-import utils.one_hot as one_hot
-from tensorflow.keras.utils import get_custom_objects
-from tensorflow.keras.models import load_model
-import tensorflow as tf
-
-def load_model_wrapper(args):
-    # read .h5 model
-    custom_objects={"multinomial_nll":losses.multinomial_nll, "tf": tf}    
-    get_custom_objects().update(custom_objects)    
-    model=load_model(args.model_h5)
-    print("got the model")
-    model.summary()
-    return model
diff --git a/src/evaluation/modisco/README.md b/src/evaluation/modisco/README.md
deleted file mode 100644
index b3182e5f..00000000
--- a/src/evaluation/modisco/README.md
+++ /dev/null
@@ -1,42 +0,0 @@
-
-# Scripts to do MODSICO on deepshap output of ChromBPNet
-
-The scripts in this folder do the following three steps (1)  Do de-novo motif discovery on the deepshap output of chrombpnet using MODISCO (2) Annotate the motifs using TOMTOM and (3) Summarize the output to a html format.
-
-## Usage
-
-```
-bash run.sh [scores_prefix] [output_dir] [score_type] [seqlets] [crop] [meme_db] [meme_logos] [vier_logos] [vier_html] [html_link]
-```
-
-The following assumptions are made with this script - make changes accordingly if the assumptions dont hold.
-
-- The following scripts are used on the output of `/src/evaluation/interpret/interpret.py`. 
-
-## Example Usage
-
-```
-bash run.sh /path/to/deepshap_scores/ /path/to/store/output/ counts/profiles 200000 1000 /oak/stanford/groups/akundaje/soumyak/motifs/motifs.meme.txt /oak/stanford/groups/akundaje/soumyak/motifs/pfms/ /oak/stanford/groups/akundaje/projects/chromatin-atlas/vierstra_logos/ http://mitra.stanford.edu/kundaje/anusri/chrombpnet_paper/vierstra_logos/  http://mitra.stanford.edu/kundaje/anusri/chrombpnet_paper/testing/
-```
-
-## Input Format
-
-- scores_prefix: This is the `output_prefix` used with `/src/evaluation/interpret/interpret.py`. 
-- score_type: This is either set to `counts` or `profile`.
-- output_dir: Path to a directory to store the output files. The script assumes that the directory already exists. Look at the output format section below to understand the files generated.
-- seqlets: Number of seqlets to use for modisco run. If using the most recent dev version of MODISCO this can be set to 200K. If using older version set to 50K. You can test the working of the script with a much smaller value - as this decides the runtime of the script.
-- crop: An integer value representing the crop length to use on the chrombpnet input. In chrombpnet we get contribution scores for 2114 length input but we will run modisco on only 1000 length input. So the default value for this parameter is set to 1000. We do this to avoid catching "AT" rich nucleosome motifs that occur more frequently on the flanks of the 2114 length input.
-- meme_db: A txt file containing the meme motifs letter probability matrix. Example file - `/oak/stanford/groups/akundaje/soumyak/motifs/motifs.meme.txt`
-- meme_logos: A directory containing meme pfms - Example file - `/oak/stanford/groups/akundaje/soumyak/motifs/pfms`
-- vier_logos: A directory with images for the pfms provided in `meme_logos`. If the image is not already present the scripts creates that image.
-- vier_html: An html link to a folder to host the images in `vier_logos`. These links are used in `score_type.motifs.html` page created below in output format section.
-- html_link: An html prefix link that is hostable. The folder `untrimmed_logos` should be hostable with this html as prefix.
-
-## Output Format
-
-- modisco_results_allChroms_`score_type`.hdf5: Modisco output `hdf5` file.
-- seqlets_`score_type`.txt: 
-- `score_type`.tomtom.tsv: Tomom output.
-- `score_type`.motifs.html: An html link where the modisco motifs are ranked based on their frequency. This html link will host html images provided in `html_link` and `vier_html`. 
-- `untrimmed_logos`: This directory will be created in `output_dir` path provided. This directory will store the motif images that are not trimmed.
-- `trimmed_logos`: This directory will be created in `output_dir` path provided. This directory wil store the motif images that are trimmed based on the default threshold of 0.3 used in the scripts. 
diff --git a/src/evaluation/modisco/run.sh b/src/evaluation/modisco/run.sh
deleted file mode 100644
index 3df0ec5e..00000000
--- a/src/evaluation/modisco/run.sh
+++ /dev/null
@@ -1,38 +0,0 @@
-# exit when any command fails
-set -e
-
-# keep track of the last executed command
-trap 'last_command=$current_command; current_command=$BASH_COMMAND' DEBUG
-# echo an error message before exiting
-trap 'echo "\"${last_command}\" command filed with exit code $?."' EXIT
-
-
-scores_prefix=$1
-output_dir=$2
-score_type=$3
-seqlets=$4
-crop=$5
-#meme_db=$6
-#meme_logos=$7
-#vier_logos=$8
-#vier_html=$9
-#html_link=${10}
-
-scores_prefix=/oak/stanford/groups/akundaje/projects/chrombpnet_paper/testing/testing
-output_dir=/oak/stanford/groups/akundaje/projects/chrombpnet_paper/testing/
-score_type=counts
-seqlets=50000
-crop=1000
-meme_db=/oak/stanford/groups/akundaje/soumyak/motifs/motifs.meme.txt
-meme_logos=/oak/stanford/groups/akundaje/soumyak/motifs/pfms/
-vier_logos=/oak/stanford/groups/akundaje/projects/chromatin-atlas/vierstra_logos/
-
-vier_html=http://mitra.stanford.edu/kundaje/anusri/chrombpnet_paper/vierstra_logos/
-html_link=http://mitra.stanford.edu/kundaje/anusri/chrombpnet_paper/testing/
-
-python run_modisco.py -s $scores_prefix -p $score_type -o $output_dir -m $seqlets -c $crop
-#python fetch_tomtom.py -m $output_dir/modisco_results_allChroms_counts.hdf5 -o $output_dir/$score_type.tomtom.tsv -d $meme_db -n 10 -th 0.3
-#python visualize_motif_matches.py -m $output_dir/modisco_results_allChroms_counts.hdf5 -t $output_dir/$score_type.tomtom.tsv -o $output_dir \
-#     -vd $vier_logos -th 0.3 -hl  $html_link -vhl $vier_html \
-#      -s $score_type -d $meme_logos
-
diff --git a/src/evaluation/variant_effect_prediction/losses.py b/src/evaluation/variant_effect_prediction/losses.py
deleted file mode 100644
index b38f8a69..00000000
--- a/src/evaluation/variant_effect_prediction/losses.py
+++ /dev/null
@@ -1,46 +0,0 @@
-import tensorflow as tf
-import tensorflow_probability as tfp
-import sys
-import pdb 
-import numpy as np 
-
-
-#from https://github.com/kundajelab/basepair/blob/cda0875571066343cdf90aed031f7c51714d991a/basepair/losses.py#L87
-def multinomial_nll(true_counts, logits):
-    """Compute the multinomial negative log-likelihood
-    Args:
-      true_counts: observed count values
-      logits: predicted logit values
-    """
-    counts_per_example = tf.reduce_sum(true_counts, axis=-1)
-    dist = tfp.distributions.Multinomial(total_count=counts_per_example,
-                                         logits=logits)
-    return (-tf.reduce_sum(dist.log_prob(true_counts)) / 
-            tf.cast(tf.shape(true_counts)[0], dtype=tf.float32))
-
-
-class MultichannelMultinomialNLL(object):
-    def __init__(self, n, weights=None):
-        self.__name__ = "MultichannelMultinomialNLL"
-        self.n = n
-        if weights is None:
-            self.weights = [1]*self.n
-        else:
-            self.weights = weights
-        #print(self.weights, self.n)
-
-
-    def __call__(self, true_counts, logits):
-        for i in range(self.n):
-            loss = multinomial_nll(true_counts[..., i], logits[..., i])
-            #print(loss)
-            if i == 0:
-                total = self.weights[i]*loss
-            else:
-                total += self.weights[i]*loss
-        return total
-
-    def get_config(self):
-        return {"n": self.n, "weights":self.weights}
-
-
diff --git a/src/helpers/hyperparameters/context.py b/src/helpers/hyperparameters/context.py
deleted file mode 100644
index 32247211..00000000
--- a/src/helpers/hyperparameters/context.py
+++ /dev/null
@@ -1,32 +0,0 @@
-import os
-import sys
-sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../../training/')))
-import utils.losses as losses
-import utils.one_hot as one_hot
-import tensorflow as tf
-import tensorflow_probability as tfp
-
-def multinomial_nll(true_counts, logits):
-    """Compute the multinomial negative log-likelihood
-    Args:
-      true_counts: observed count values [B x L]
-      logits: predicted logit values [B x L]
-    """
-    counts_per_example = tf.reduce_sum(true_counts, axis=-1)
-    dist = tfp.distributions.Multinomial(total_count=counts_per_example,
-                                         logits=logits)
-    return (-tf.reduce_sum(dist.log_prob(true_counts)) / 
-            tf.cast(tf.shape(true_counts)[0], dtype=tf.float32))
-
-def load_model_wrapper(model_h5):
-    # read .h5 model
-    import tensorflow as tf
-    from tensorflow.keras.utils import get_custom_objects
-    from tensorflow.keras.models import load_model
-    custom_objects={"tf": tf, "multinomial_nll":multinomial_nll}    
-    get_custom_objects().update(custom_objects)    
-    model=load_model(model_h5)
-    print("got the model")
-    model.summary()
-    return model
-
diff --git a/src/helpers/make_chr_splits/splits.py b/src/helpers/make_chr_splits/splits.py
deleted file mode 100644
index aa85d259..00000000
--- a/src/helpers/make_chr_splits/splits.py
+++ /dev/null
@@ -1,39 +0,0 @@
-import json
-import argparse
-import os
-
-parser = argparse.ArgumentParser()
-parser.add_argument("-o", "--output_dir", type=str, required=True, help="Path to store the fold information")
-args = parser.parse_args()
-
-# mention what the outputformat should look like for further editing
-
-chroms = ['chr1','chr2','chr3','chr4','chr5','chr6','chr7','chr8', 'chr9','chr10', 'chr11','chr12','chr13','chr14','chr15','chr16','chr17','chr18','chr19','chr20','chr21','chr22','chrX','chrY']
-splits=dict()
-
-splits[0]={'test':['chr1', 'chr3', 'chr6'],
-           'valid':['chr8', 'chr20']}
-splits[0]['train'] = [chrom for chrom in chroms if chrom not in splits[0]['test']+splits[0]['valid']]
-json.dump(splits[0], open(os.path.join(args.output_dir, "fold_0.json"),"w"), indent=4)
-
-splits[1]={'test':['chr2', 'chr8', 'chr9', 'chr16'],
-           'valid':[ 'chr12', 'chr17']}
-splits[1]['train'] = [chrom for chrom in chroms if chrom not in splits[1]['test']+splits[1]['valid']]
-json.dump(splits[1], open(os.path.join(args.output_dir, "fold_1.json"),"w"), indent=4)
-
-splits[2]={'test':['chr4','chr11', 'chr12', 'chr15', 'chrY'],
-            'valid':['chr22','chr7']}
-splits[2]['train'] = [chrom for chrom in chroms if chrom not in splits[2]['test']+splits[2]['valid']]
-json.dump(splits[2], open(os.path.join(args.output_dir, "fold_2.json"),"w"), indent=4)
-
-
-splits[3]={'test':['chr5','chr10','chr14', 'chr18', 'chr20', 'chr22'],
-            'valid':['chr6', 'chr21']}
-splits[3]['train'] = [chrom for chrom in chroms if chrom not in splits[3]['test']+splits[3]['valid']]
-json.dump(splits[3], open(os.path.join(args.output_dir, "fold_3.json"),"w"), indent=4)
-
-
-splits[4]={'test':['chr7','chr13','chr17', 'chr19', 'chr21', 'chrX'],
-           'valid':['chr10','chr18']}
-splits[4]['train'] = [chrom for chrom in chroms if chrom not in splits[4]['test']+splits[4]['valid']]
-json.dump(splits[4], open(os.path.join(args.output_dir, "fold_4.json"),"w"), indent=4)
diff --git a/src/helpers/preprocessing/analysis/one_hot.py b/src/helpers/preprocessing/analysis/one_hot.py
deleted file mode 100644
index db1db57d..00000000
--- a/src/helpers/preprocessing/analysis/one_hot.py
+++ /dev/null
@@ -1,56 +0,0 @@
-# from https://gist.github.com/amtseng/010dd522daaabc92b014f075a34a0a0b
-import numpy as np
-
-def dna_to_one_hot(seqs):
-    """
-    Converts a list of DNA ("ACGT") sequences to one-hot encodings, where the
-    position of 1s is ordered alphabetically by "ACGT". `seqs` must be a list
-    of N strings, where every string is the same length L. Returns an N x L x 4
-    NumPy array of one-hot encodings, in the same order as the input sequences.
-    All bases will be converted to upper-case prior to performing the encoding.
-    Any bases that are not "ACGT" will be given an encoding of all 0s.
-    """
-    seq_len = len(seqs[0])
-    assert np.all(np.array([len(s) for s in seqs]) == seq_len)
-
-    # Join all sequences together into one long string, all uppercase
-    seq_concat = "".join(seqs).upper() + "ACGT"
-    # Add one example of each base, so np.unique doesn't miss indices later
-
-    one_hot_map = np.identity(5)[:, :-1]
-
-    # Convert string into array of ASCII character codes;
-    base_vals = np.frombuffer(bytearray(seq_concat, "utf8"), dtype=np.int8)
-
-    # Anything that's not an A, C, G, or T gets assigned a higher code
-    base_vals[~np.isin(base_vals, np.array([65, 67, 71, 84]))] = 85
-
-    # Convert the codes into indices in [0, 4], in ascending order by code
-    _, base_inds = np.unique(base_vals, return_inverse=True)
-
-    # Get the one-hot encoding for those indices, and reshape back to separate
-    return one_hot_map[base_inds[:-4]].reshape((len(seqs), seq_len, 4))
-
-
-def one_hot_to_dna(one_hot):
-    """
-    Converts a one-hot encoding into a list of DNA ("ACGT") sequences, where the
-    position of 1s is ordered alphabetically by "ACGT". `one_hot` must be an
-    N x L x 4 array of one-hot encodings. Returns a lits of N "ACGT" strings,
-    each of length L, in the same order as the input array. The returned
-    sequences will only consist of letters "A", "C", "G", "T", or "N" (all
-    upper-case). Any encodings that are all 0s will be translated to "N".
-    """
-    bases = np.array(["A", "C", "G", "T", "N"])
-    # Create N x L array of all 5s
-    one_hot_inds = np.tile(one_hot.shape[2], one_hot.shape[:2])
-
-    # Get indices of where the 1s are
-    batch_inds, seq_inds, base_inds = np.where(one_hot)
-
-    # In each of the locations in the N x L array, fill in the location of the 1
-    one_hot_inds[batch_inds, seq_inds] = base_inds
-
-    # Fetch the corresponding base for each position using indexing
-    seq_array = bases[one_hot_inds]
-    return ["".join(seq) for seq in seq_array]
\ No newline at end of file
diff --git a/src/training/utils/one_hot.py b/src/training/utils/one_hot.py
deleted file mode 100644
index 4fadf92a..00000000
--- a/src/training/utils/one_hot.py
+++ /dev/null
@@ -1,61 +0,0 @@
-"""
-Written by Alex Tseng
-
-https://gist.github.com/amtseng/010dd522daaabc92b014f075a34a0a0b
-"""
-
-import numpy as np
-
-def dna_to_one_hot(seqs):
-    """
-    Converts a list of DNA ("ACGT") sequences to one-hot encodings, where the
-    position of 1s is ordered alphabetically by "ACGT". `seqs` must be a list
-    of N strings, where every string is the same length L. Returns an N x L x 4
-    NumPy array of one-hot encodings, in the same order as the input sequences.
-    All bases will be converted to upper-case prior to performing the encoding.
-    Any bases that are not "ACGT" will be given an encoding of all 0s.
-    """
-    seq_len = len(seqs[0])
-    assert np.all(np.array([len(s) for s in seqs]) == seq_len)
-
-    # Join all sequences together into one long string, all uppercase
-    seq_concat = "".join(seqs).upper() + "ACGT"
-    # Add one example of each base, so np.unique doesn't miss indices later
-
-    one_hot_map = np.identity(5)[:, :-1].astype(np.int8)
-
-    # Convert string into array of ASCII character codes;
-    base_vals = np.frombuffer(bytearray(seq_concat, "utf8"), dtype=np.int8)
-
-    # Anything that's not an A, C, G, or T gets assigned a higher code
-    base_vals[~np.isin(base_vals, np.array([65, 67, 71, 84]))] = 85
-
-    # Convert the codes into indices in [0, 4], in ascending order by code
-    _, base_inds = np.unique(base_vals, return_inverse=True)
-
-    # Get the one-hot encoding for those indices, and reshape back to separate
-    return one_hot_map[base_inds[:-4]].reshape((len(seqs), seq_len, 4))
-
-
-def one_hot_to_dna(one_hot):
-    """
-    Converts a one-hot encoding into a list of DNA ("ACGT") sequences, where the
-    position of 1s is ordered alphabetically by "ACGT". `one_hot` must be an
-    N x L x 4 array of one-hot encodings. Returns a lits of N "ACGT" strings,
-    each of length L, in the same order as the input array. The returned
-    sequences will only consist of letters "A", "C", "G", "T", or "N" (all
-    upper-case). Any encodings that are all 0s will be translated to "N".
-    """
-    bases = np.array(["A", "C", "G", "T", "N"])
-    # Create N x L array of all 5s
-    one_hot_inds = np.tile(one_hot.shape[2], one_hot.shape[:2])
-
-    # Get indices of where the 1s are
-    batch_inds, seq_inds, base_inds = np.where(one_hot)
-
-    # In each of the locations in the N x L array, fill in the location of the 1
-    one_hot_inds[batch_inds, seq_inds] = base_inds
-
-    # Fetch the corresponding base for each position using indexing
-    seq_array = bases[one_hot_inds]
-    return ["".join(seq) for seq in seq_array]
diff --git a/step1_download_bams_and_peaks.sh b/step1_download_bams_and_peaks.sh
old mode 100644
new mode 100755
index 49dad8c7..268a8764
--- a/step1_download_bams_and_peaks.sh
+++ b/step1_download_bams_and_peaks.sh
@@ -1,10 +1,16 @@
+#!/bin/bash
+
+echo "WARNING: If upgrading from v1.0 or v1.1 to v1.2. Note that chrombpnet has undergone linting to generate a modular structure for release on pypi.Hard-coded script paths are no longer necessary. Please refer to the updated README (below) to ensure your script calls are compatible with v1.2"
+
+
 # exit when any command fails
 set -e
+set -o pipefail
 # keep track of the last executed command
 trap 'last_command=$current_command; current_command=$BASH_COMMAND' DEBUG
 # echo an error message before exiting
-trap 'echo "\"${last_command}\" command filed with exit code $?."' EXIT
-data_dir=$1
+trap 'echo "\"${last_command}\" command failed with exit code $?."' EXIT
+data_dir=${1?param missing - data_dir}
 
 # download bam
 wget https://www.encodeproject.org/files/ENCFF077FBI/@@download/ENCFF077FBI.bam -O $data_dir/rep1.bam
@@ -20,7 +26,7 @@ wget https://www.encodeproject.org/files/ENCFF333TAT/@@download/ENCFF333TAT.bed.
 
 # download reference data
 wget https://www.encodeproject.org/files/GRCh38_no_alt_analysis_set_GCA_000001405.15/@@download/GRCh38_no_alt_analysis_set_GCA_000001405.15.fasta.gz -O $data_dir/hg38.fa.gz
-gunzip $data_dir/hg38.fa.gz
+yes n | gunzip $data_dir/hg38.fa.gz
 
 # download reference chromsome sizes
 wget https://www.encodeproject.org/files/GRCh38_EBV.chrom.sizes/@@download/GRCh38_EBV.chrom.sizes.tsv -O $data_dir/hg38.chrom.sizes
diff --git a/step2_make_bigwigs_from_bams.sh b/step2_make_bigwigs_from_bams.sh
old mode 100644
new mode 100755
index 2032d04f..f74f2fa7
--- a/step2_make_bigwigs_from_bams.sh
+++ b/step2_make_bigwigs_from_bams.sh
@@ -1,18 +1,21 @@
 #!/bin/bash
 
+echo "WARNING: If upgrading from v1.0 or v1.1 to v1.2. Note that chrombpnet has undergone linting to generate a modular structure for release on pypi.Hard-coded script paths are no longer necessary. Please refer to the updated README (below) to ensure your script calls are compatible with v1.2"
+
 # exit when any command fails
 set -e
+set -o pipefail
 
 # keep track of the last executed command
 trap 'last_command=$current_command; current_command=$BASH_COMMAND' DEBUG
 # echo an error message before exiting
-trap 'echo "\"${last_command}\" command filed with exit code $?."' EXIT
+trap 'echo "\"${last_command}\" command failed with exit code $?."' EXIT
 
-in_bam=$1
-bigwig_prefix=$2
-data_type=$3
-reference_fasta=$4
-chrom_sizes=$5
+in_bam=${1?param missing - in_bam}
+bigwig_prefix=${2?param missing - bigwig_prefix}
+data_type=${3?param missing - data_type}
+reference_fasta=${4?param missing - reference_fasta}
+chrom_sizes=${5?param missing - chrom_sizes}
 
 function timestamp {
     # Function to get the current time with the new line character
@@ -25,7 +28,7 @@ function timestamp {
 logfile=$bigwig_prefix"_preprocessing.log"
 touch $logfile
 
-bash $PWD/src/helpers/preprocessing/bam_to_bigwig.sh $in_bam $bigwig_prefix $data_type $chrom_sizes $logfile
+bam_to_bigwig.sh $in_bam $bigwig_prefix $data_type $chrom_sizes $logfile
 
-echo $( timestamp ): "python $PWD/src/helpers/preprocessing/analysis/build_pwm_from_bigwig.py -i $bigwig_prefix_unstranded.bw -g $reference_fasta -o $bigwig_prefix_bias_pwm -c chr20 -cz $chrom_sizes" | tee -a $logfile
-python $PWD/src/helpers/preprocessing/analysis/build_pwm_from_bigwig.py -i $bigwig_prefix"_unstranded.bw" -g $reference_fasta -o $bigwig_prefix"_bias_pwm" -c "chr20" -cz $chrom_sizes 
+echo $( timestamp ): "chrombpnet_pwm_from_bigwig -i $bigwig_prefix_unstranded.bw -g $reference_fasta -o $bigwig_prefix_bias_pwm -c chr20 -cz $chrom_sizes" | tee -a $logfile
+chrombpnet_pwm_from_bigwig -i $bigwig_prefix"_unstranded.bw" -g $reference_fasta -o $bigwig_prefix"_bias_pwm" -c "chr20" -cz $chrom_sizes 
diff --git a/step3_get_background_regions.sh b/step3_get_background_regions.sh
old mode 100644
new mode 100755
index 57e2a7e8..8193fa66
--- a/step3_get_background_regions.sh
+++ b/step3_get_background_regions.sh
@@ -1,20 +1,24 @@
 #!/bin/bash
+
+echo "WARNING: If upgrading from v1.0 or v1.1 to v1.2. Note that chrombpnet has undergone linting to generate a modular structure for release on pypi.Hard-coded script paths are no longer necessary. Please refer to the updated README (below) to ensure your script calls are compatible with v1.2"
+
 # exit when any command fails
 set -e
+set -o pipefail
 
 # keep track of the last executed command
 trap 'last_command=$current_command; current_command=$BASH_COMMAND' DEBUG
 # echo an error message before exiting
-trap 'echo "\"${last_command}\" command filed with exit code $?."' EXIT
+trap 'echo "\"${last_command}\" command failed with exit code $?."' EXIT
 
-reference_fasta=$1
-chrom_sizes=$2
-blacklist_region=$3
-overlap_peak=$4
-inputlen=$5
-genomewide_gc=$6
-output_dir=$7
-fold=$8
+reference_fasta=${1?param missing - reference_fasta}
+chrom_sizes=${2?param missing - chrom_sizes}
+blacklist_region=${3?param missing - blaklist_region}
+overlap_peak=${4?param missing - overlap_peak}
+inputlen=${5?param missing - inputlen}
+genomewide_gc=${6?param missing - genomewide_gc}
+output_dir=${7?param missing - output_dir} 
+fold=${8?param missing - fold}
 
 function timestamp {
     # Function to get the current time with the new line character
@@ -48,7 +52,7 @@ exclude_bed=$output_dir/exclude.bed
 
 # create regions of size inputlen that do not fall in exclude bed and that gc-match with the given overlap peaks
 # create as many regions as there are in overlap peaks bed file
-bash $PWD/src/helpers/make_gc_matched_negatives/run.sh $overlap_peak $exclude_bed $inputlen $output_dir $reference_fasta $genomewide_gc $fold $chrom_sizes $logfile
+make_gc_matched_negatives.sh  $overlap_peak $exclude_bed $inputlen $output_dir $reference_fasta $genomewide_gc $fold $chrom_sizes $logfile
 # make a dummy summit file - rest of the pipeline uses this format
 echo $( timestamp ): "awk -v OFS=\"\t\" '{print \$1, \$2, \$3, \".\",  \".\", \".\", \".\", \".\", \".\", \"1057\"}\' $output_dir/negatives.bed > $output_dir/negatives_with_summit.bed" | tee -a $logfile
 awk -v OFS="\t" '{print $1, $2, $3, ".",  ".", ".", ".", ".", ".", "1057"}' $output_dir/negatives.bed > $output_dir/negatives_with_summit.bed
diff --git a/step4_train_bias_model.sh b/step4_train_bias_model.sh
old mode 100644
new mode 100755
index 60bcfdaa..66a56334
--- a/step4_train_bias_model.sh
+++ b/step4_train_bias_model.sh
@@ -1,25 +1,31 @@
+#!/bin/bash
+
+echo "WARNING: If upgrading from v1.0 or v1.1 to v1.2. Note that chrombpnet has undergone linting to generate a modular structure for release on pypi.Hard-coded script paths are no longer necessary. Please refer to the updated README (below) to ensure your script calls are compatible with v1.2"
+
 # exit when any command fails
 set -e
+set -o pipefail
 
 # keep track of the last executed command
 trap 'last_command=$current_command; current_command=$BASH_COMMAND' DEBUG
 # echo an error message before exiting
-trap 'echo "\"${last_command}\" command filed with exit code $?."' EXIT
+trap 'echo "\"${last_command}\" command failed with exit code $?."' EXIT
 
-reference_fasta=$1
-bigwig_path=$2
-overlap_peak=$3
-nonpeaks=$4
-fold=$5
-bias_threshold_factor=$6
-output_dir=$7
-logfile=$8
+reference_fasta=${1?param missing - reference_fasta}
+bigwig_path=${2?param missing - bigwig_path}
+overlap_peak=${3?param missing - overlap_peak}
+nonpeaks=${4?param missing - nonpeaks}
+fold=${5?param missing - fold}
+bias_threshold_factor=${6?param missing - bias_threshold_factor}
+output_dir=${7?param missing - output_dir}
+filters=${8:-128}
+n_dilation_layers=${9:-4}
+seed=${10:-1234}
+logfile=${11}
 
 # defaults
 inputlen=2114
 outputlen=1000
-filters=128
-n_dilation_layers=4
 
 function timestamp {
     # Function to get the current time with the new line character
@@ -42,7 +48,7 @@ fi
 # (2) filters non peaks based on the given bias threshold factor
 # (3) Calculates the counts loss weight 
 # (4) Creates a TSV file that can be loaded into the next step
-echo $( timestamp ): "python $PWD/src/helpers/hyperparameters/find_bias_hyperparams.py \\
+echo $( timestamp ): "chrombpnet_bias_hyperparams \\
        --genome=$reference_fasta \\
        --bigwig=$bigwig_path \\
        --peaks=$overlap_peak \\
@@ -51,56 +57,59 @@ echo $( timestamp ): "python $PWD/src/helpers/hyperparameters/find_bias_hyperpar
        --chr_fold_path=$fold \\
        --inputlen=$inputlen \\
        --outputlen=$outputlen \\
-       --max_jitter=50 \\
+       --max_jitter=0 \\
        --filters=$filters \\
        --n_dilation_layers=$n_dilation_layers \\
        --bias_threshold_factor=$bias_threshold_factor \\
        --output_dir $output_dir" | tee -a $logfile
 
-python $PWD/src/helpers/hyperparameters/find_bias_hyperparams.py \
-       --genome=$reference_fasta \
-       --bigwig=$bigwig_path \
-       --peaks=$overlap_peak \
-       --nonpeaks=$nonpeaks \
-       --outlier_threshold=0.99 \
-       --chr_fold_path=$fold \
-       --inputlen=$inputlen \
-       --outputlen=$outputlen \
-       --max_jitter=50 \
-       --filters=$filters \
-       --n_dilation_layers=$n_dilation_layers \
-       --bias_threshold_factor=$bias_threshold_factor \
-       --output_dir $output_dir | tee -a $logfile
+chrombpnet_bias_hyperparams \
+    --genome=$reference_fasta \
+    --bigwig=$bigwig_path \
+    --peaks=$overlap_peak \
+    --nonpeaks=$nonpeaks \
+    --outlier_threshold=0.99 \
+    --chr_fold_path=$fold \
+    --inputlen=$inputlen \
+    --outputlen=$outputlen \
+    --max_jitter=0 \
+    --filters=$filters \
+    --n_dilation_layers=$n_dilation_layers \
+    --bias_threshold_factor=$bias_threshold_factor \
+    --output_dir $output_dir | tee -a $logfile
 
 # this script does the following -  
 # (1) trains a model on the given peaks/nonpeaks
-# (2) The parameters file input to this script should be TSV seperated 
-echo $( timestamp ): "python $PWD/src/training/train.py \\
+# (2) The parameters file input to this script should be TSV seperated
+bpnet_model_path=`which bpnet_model.py`
+echo $( timestamp ): "chrombpnet_train \\
        --genome=$reference_fasta \\
        --bigwig=$bigwig_path \\
        --nonpeaks=$output_dir/filtered.bias_nonpeaks.bed \\
        --params=$output_dir/bias_model_params.tsv \\
        --output_prefix=$output_dir/bias \\
        --chr_fold_path=$fold \\
+       --seed=$seed \\
        --batch_size=64 \\
-       --architecture_from_file=$PWD/src/training/models/bpnet_model.py \\
+       --architecture_from_file=$bpnet_model_path \\
        --trackables logcount_predictions_loss loss logits_profile_predictions_loss val_logcount_predictions_loss val_loss val_logits_profile_predictions_loss" | tee -a $logfile
 
-python $PWD/src/training/train.py \
-       --genome=$reference_fasta \
-       --bigwig=$bigwig_path \
-       --nonpeaks=$output_dir/filtered.bias_nonpeaks.bed \
-       --params=$output_dir/bias_model_params.tsv \
-       --output_prefix=$output_dir/bias \
-       --chr_fold_path=$fold \
-       --batch_size=64 \
-       --architecture_from_file=$PWD/src/training/models/bpnet_model.py \
-       --trackables logcount_predictions_loss loss logits_profile_predictions_loss val_logcount_predictions_loss val_loss val_logits_profile_predictions_loss  | tee -a $logfile
+chrombpnet_train \
+    --genome=$reference_fasta \
+    --bigwig=$bigwig_path \
+    --nonpeaks=$output_dir/filtered.bias_nonpeaks.bed \
+    --params=$output_dir/bias_model_params.tsv \
+    --output_prefix=$output_dir/bias \
+    --chr_fold_path=$fold \
+    --seed=$seed \
+    --batch_size=64 \
+    --architecture_from_file=$bpnet_model_path \
+    --trackables logcount_predictions_loss loss logits_profile_predictions_loss val_logcount_predictions_loss val_loss val_logits_profile_predictions_loss  | tee -a $logfile
 
 # predictions and metrics on the bias model trained
-echo $( timestamp ): "python $PWD/src/training/predict.py \\
-        --genome=$reference_fasta \\
-        --bigwig=$bigwig_path \\
+echo $( timestamp ): "chrombpnet_predict \\
+        --genome=$reference_fasta \\	 
+        --bigwig=$bigwig_path \\  
         --nonpeaks=$output_dir/filtered.bias_nonpeaks.bed \\
         --chr_fold_path=$fold \\
         --inputlen=$inputlen \\
@@ -109,13 +118,13 @@ echo $( timestamp ): "python $PWD/src/training/predict.py \\
         --batch_size=256 \\
         --model_h5=$output_dir/bias.h5" | tee -a $logfile
 
-python $PWD/src/training/predict.py \
-        --genome=$reference_fasta \
-        --bigwig=$bigwig_path \
-        --nonpeaks=$output_dir/filtered.bias_nonpeaks.bed \
-        --chr_fold_path=$fold \
-        --inputlen=$inputlen \
-        --outputlen=$outputlen \
-        --output_prefix=$output_dir/bias \
-        --batch_size=256 \
-        --model_h5=$output_dir/bias.h5 | tee -a $logfile
+chrombpnet_predict \
+    --genome=$reference_fasta \
+    --bigwig=$bigwig_path \
+    --nonpeaks=$output_dir/filtered.bias_nonpeaks.bed \
+    --chr_fold_path=$fold \
+    --inputlen=$inputlen \
+    --outputlen=$outputlen \
+    --output_prefix=$output_dir/bias \
+    --batch_size=256 \
+    --model_h5=$output_dir/bias.h5 | tee -a $logfile
diff --git a/step5_interpret_bias_model.sh b/step5_interpret_bias_model.sh
old mode 100644
new mode 100755
index 3f0170ef..ea67cb1d
--- a/step5_interpret_bias_model.sh
+++ b/step5_interpret_bias_model.sh
@@ -1,24 +1,29 @@
+#!/bin/bash
+
+echo "WARNING: If upgrading from v1.0 or v1.1 to v1.2. Note that chrombpnet has undergone linting to generate a modular structure for release on pypi.Hard-coded script paths are no longer necessary. Please refer to the updated README (below) to ensure your script calls are compatible with v1.2"
+
 # exit when any command fails
 set -e
+set -o pipefail
 
 # keep track of the last executed command
 trap 'last_command=$current_command; current_command=$BASH_COMMAND' DEBUG
 # echo an error message before exiting
-trap 'echo "\"${last_command}\" command filed with exit code $?."' EXIT
-reference_fasta=$1
-regions=$2
-model_h5=$3
-output_dir=$4
+trap 'echo "\"${last_command}\" command failed with exit code $?."' EXIT
+reference_fasta=${1?param missing - reference_fasta}
+regions=${2?param missing - regions}
+model_h5=${3?param missing - model_h5}
+output_dir=${4?param missing - output_dir}
 
 ## deepshap run
 
-python $PWD/src/evaluation/interpret/interpret.py \
-       --genome=$reference_fasta \
-       --regions=$regions \
-       --output_prefix=$output_dir/bias \
-       --model_h5=$model_h5 \
+chrombpnet_deepshap \
+    --genome=$reference_fasta \
+    --regions=$regions \
+    --output_prefix=$output_dir/bias \
+    --model_h5=$model_h5 \
 
 ## modisco run
 
-python src/evaluation/modisco/run_modisco.py -s $output_dir/bias -p "profile" -o $output_dir -m 50000 -c 500
-python src/evaluation/modisco/run_modisco.py -s $output_dir/bias -p "counts" -o $output_dir -m 50000 -c 500
+chrombpnet_modisco -s $output_dir/bias -p "profile" -o $output_dir -m 50000 -c 500
+chrombpnet_modisco -s $output_dir/bias -p "counts" -o $output_dir -m 50000 -c 500
diff --git a/step6_train_chrombpnet_model.sh b/step6_train_chrombpnet_model.sh
old mode 100644
new mode 100755
index 7e0023c1..e9b5106e
--- a/step6_train_chrombpnet_model.sh
+++ b/step6_train_chrombpnet_model.sh
@@ -1,20 +1,26 @@
+#!/bin/bash
+
+echo "WARNING: If upgrading from v1.0 or v1.1 to v1.2. Note that chrombpnet has undergone linting to generate a modular structure for release on pypi.Hard-coded script paths are no longer necessary. Please refer to the updated README (below) to ensure your script calls are compatible with v1.2"
+
 # exit when any command fails
 set -e
+set -o pipefail
 
 # keep track of the last executed command
 trap 'last_command=$current_command; current_command=$BASH_COMMAND' DEBUG
 # echo an error message before exiting
-trap 'echo "\"${last_command}\" command filed with exit code $?."' EXIT
+trap 'echo "\"${last_command}\" command failed with exit code $?."' EXIT
 
-reference_fasta=$1
-bigwig_path=$2
-overlap_peak=$3
-nonpeaks=$4
-fold=$5
-bias_model=$6
-output_dir=$7
-data_type=$8
-logfile=$9
+reference_fasta=${1?param missing - reference_fasta}
+bigwig_path=${2?param missing - bigwig_path }
+overlap_peak=${3?param missing - overlap_peak}
+nonpeaks=${4?param missing - nonpeaks}
+fold=${5?param missing - fold}
+bias_model=${6?param missing - bias_model}
+output_dir=${7?param missing - output_dir}
+data_type=${8?param missing - data_type}
+seed=${9:-1234}
+logfile=$10 #optional
 
 # defaults
 inputlen=2114
@@ -45,7 +51,7 @@ fi
 # (2) scales the given bias model on the non-peaks
 # (3) Calculates the counts loss weight 
 # (4) Creates a TSV file that can be loaded into the next step
-echo $( timestamp ): "python $PWD/src/helpers/hyperparameters/find_chrombpnet_hyperparams.py \\
+echo $( timestamp ): "chrombpnet_hyperparams \\
        --genome=$reference_fasta \\
        --bigwig=$bigwig_path \\
        --peaks=$overlap_peak \\
@@ -60,26 +66,27 @@ echo $( timestamp ): "python $PWD/src/helpers/hyperparameters/find_chrombpnet_hy
        --n_dilation_layers=$n_dilation_layers \\
        --bias_model_path=$bias_model \\
        --output_dir=$output_dir " | tee -a $logfile
-python $PWD/src/helpers/hyperparameters/find_chrombpnet_hyperparams.py \
-       --genome=$reference_fasta \
-       --bigwig=$bigwig_path \
-       --peaks=$overlap_peak \
-       --nonpeaks=$nonpeaks \
-       --outlier_threshold=0.99 \
-       --chr_fold_path=$fold \
-       --negative_sampling_ratio=$negative_sampling_ratio \
-       --inputlen=$inputlen \
-       --outputlen=$outputlen \
-       --max_jitter=500 \
-       --filters=$filters \
-       --n_dilation_layers=$n_dilation_layers \
-       --bias_model_path=$bias_model \
-       --output_dir=$output_dir | tee -a $logfile
+chrombpnet_hyperparams \
+    --genome=$reference_fasta \
+    --bigwig=$bigwig_path \
+    --peaks=$overlap_peak \
+    --nonpeaks=$nonpeaks \
+    --outlier_threshold=0.99 \
+    --chr_fold_path=$fold \
+    --negative_sampling_ratio=$negative_sampling_ratio \
+    --inputlen=$inputlen \
+    --outputlen=$outputlen \
+    --max_jitter=500 \
+    --filters=$filters \
+    --n_dilation_layers=$n_dilation_layers \
+    --bias_model_path=$bias_model \
+    --output_dir=$output_dir | tee -a $logfile
 
-# # this script does the following -  
-# # (1) trains a model on the given peaks/nonpeaks
-# # (2) The parameters file input to this script should be TSV seperatedp
-echo $( timestamp ): "python $PWD/src/training/train.py \\
+## this script does the following -  
+# (1) trains a model on the given peaks/nonpeaks
+# (2) The parameters file input to this script should be TSV seperatedp
+chrombpnet_with_bias_model_path=`which chrombpnet_with_bias_model.py`
+echo $( timestamp ): "chrombpnet_train \\
        --genome=$reference_fasta \\
        --bigwig=$bigwig_path \\
        --peaks=$output_dir/filtered.peaks.bed \\
@@ -87,23 +94,26 @@ echo $( timestamp ): "python $PWD/src/training/train.py \\
        --params=$output_dir/chrombpnet_model_params.tsv \\
        --output_prefix=$output_dir/chrombpnet \\
        --chr_fold_path=$fold \\
+       --seed=$seed \\
        --batch_size=64 \\
-       --architecture_from_file=$PWD/src/training/models/chrombpnet_with_bias_model.py \\
+       --architecture_from_file=$chrombpnet_with_bias_model_path \\
        --trackables logcount_predictions_loss loss logits_profile_predictions_loss val_logcount_predictions_loss val_loss val_logits_profile_predictions_loss" | tee -a $logfile
-python $PWD/src/training/train.py \
-       --genome=$reference_fasta \
-       --bigwig=$bigwig_path \
-       --peaks=$output_dir/filtered.peaks.bed \
-       --nonpeaks=$output_dir/filtered.nonpeaks.bed \
-       --params=$output_dir/chrombpnet_model_params.tsv \
-       --output_prefix=$output_dir/chrombpnet \
-       --chr_fold_path=$fold \
-       --batch_size=64 \
-       --architecture_from_file=$PWD/src/training/models/chrombpnet_with_bias_model.py \
-       --trackables logcount_predictions_loss loss logits_profile_predictions_loss val_logcount_predictions_loss val_loss val_logits_profile_predictions_loss | tee -a $logfile
 
-# # # predictions and metrics on the chrombpnet model trained
-echo $( timestamp ): "python $PWD/src/training/predict.py \\
+chrombpnet_train \
+    --genome=$reference_fasta \
+    --bigwig=$bigwig_path \
+    --peaks=$output_dir/filtered.peaks.bed \
+    --nonpeaks=$output_dir/filtered.nonpeaks.bed \
+    --params=$output_dir/chrombpnet_model_params.tsv \
+    --output_prefix=$output_dir/chrombpnet \
+    --chr_fold_path=$fold \
+    --seed=$seed \
+    --batch_size=64 \
+    --architecture_from_file=$chrombpnet_with_bias_model_path \
+    --trackables logcount_predictions_loss loss logits_profile_predictions_loss val_logcount_predictions_loss val_loss val_logits_profile_predictions_loss | tee -a $logfile
+
+#predictions and metrics on the chrombpnet model trained
+echo $( timestamp ): "chrombpnet_predict \\
         --genome=$reference_fasta \\
         --bigwig=$bigwig_path \\
         --peaks=$output_dir/filtered.peaks.bed \\
@@ -114,20 +124,20 @@ echo $( timestamp ): "python $PWD/src/training/predict.py \\
         --output_prefix=$output_dir/chrombpnet \\
         --batch_size=256 \\
         --model_h5=$output_dir/chrombpnet.h5" | tee -a $logfile
-python $PWD/src/training/predict.py \
-        --genome=$reference_fasta \
-        --bigwig=$bigwig_path \
-        --peaks=$output_dir/filtered.peaks.bed \
-        --nonpeaks=$output_dir/filtered.nonpeaks.bed \
-        --chr_fold_path=$fold \
-        --inputlen=$inputlen \
-        --outputlen=$outputlen \
-        --output_prefix=$output_dir/chrombpnet \
-        --batch_size=256 \
-        --model_h5=$output_dir/chrombpnet.h5 | tee -a $logfile
+chrombpnet_predict \
+    --genome=$reference_fasta \
+    --bigwig=$bigwig_path \
+    --peaks=$output_dir/filtered.peaks.bed \
+    --nonpeaks=$output_dir/filtered.nonpeaks.bed \
+    --chr_fold_path=$fold \
+    --inputlen=$inputlen \
+    --outputlen=$outputlen \
+    --output_prefix=$output_dir/chrombpnet \
+    --batch_size=256 \
+    --model_h5=$output_dir/chrombpnet.h5 | tee -a $logfile
 
-# # # predictions and metrics on the chrombpnet model without bias trained
-echo $( timestamp ): "python $PWD/src/training/predict.py \\
+# predictions and metrics on the chrombpnet model without bias trained
+echo $( timestamp ): "chrombpnet_predict \\
         --genome=$reference_fasta \\
         --bigwig=$bigwig_path \\
         --peaks=$output_dir/filtered.peaks.bed \\
@@ -138,20 +148,20 @@ echo $( timestamp ): "python $PWD/src/training/predict.py \\
         --output_prefix=$output_dir/chrombpnet_wo_bias \\
         --batch_size=256 \\
         --model_h5=$output_dir/chrombpnet_wo_bias.h5 " | tee -a $logfile
-python $PWD/src/training/predict.py \
-        --genome=$reference_fasta \
-        --bigwig=$bigwig_path \
-        --peaks=$output_dir/filtered.peaks.bed \
-        --nonpeaks=$output_dir/filtered.nonpeaks.bed \
-        --chr_fold_path=$fold \
-        --inputlen=$inputlen \
-        --outputlen=$outputlen \
-        --output_prefix=$output_dir/chrombpnet_wo_bias \
-        --batch_size=256 \
-        --model_h5=$output_dir/chrombpnet_wo_bias.h5 | tee -a $logfile
+chrombpnet_predict \
+    --genome=$reference_fasta \
+    --bigwig=$bigwig_path \
+    --peaks=$output_dir/filtered.peaks.bed \
+    --nonpeaks=$output_dir/filtered.nonpeaks.bed \
+    --chr_fold_path=$fold \
+    --inputlen=$inputlen \
+    --outputlen=$outputlen \
+    --output_prefix=$output_dir/chrombpnet_wo_bias \
+    --batch_size=256 \
+    --model_h5=$output_dir/chrombpnet_wo_bias.h5 | tee -a $logfile
 
-# # # predictions and metrics on the bias model trained
-echo $( timestamp ): "python $PWD/src/training/predict.py \\
+#predictions and metrics on the bias model trained
+echo $( timestamp ): "chrombpnet_predict \\
         --genome=$reference_fasta \\
         --bigwig=$bigwig_path \\
         --peaks=$output_dir/filtered.peaks.bed \\
@@ -162,108 +172,115 @@ echo $( timestamp ): "python $PWD/src/training/predict.py \\
         --output_prefix=$output_dir/bias \\
         --batch_size=256 \\
         --model_h5=$output_dir/bias_model_scaled.h5" | tee -a $logfile
-python $PWD/src/training/predict.py \
-        --genome=$reference_fasta \
-        --bigwig=$bigwig_path \
-        --peaks=$output_dir/filtered.peaks.bed \
-        --nonpeaks=$output_dir/filtered.nonpeaks.bed \
-        --chr_fold_path=$fold \
-        --inputlen=$inputlen \
-        --outputlen=$outputlen \
-        --output_prefix=$output_dir/bias \
-        --batch_size=256 \
-        --model_h5=$output_dir/bias_model_scaled.h5 | tee -a $logfile
+chrombpnet_predict \
+    --genome=$reference_fasta \
+    --bigwig=$bigwig_path \
+    --peaks=$output_dir/filtered.peaks.bed \
+    --nonpeaks=$output_dir/filtered.nonpeaks.bed \
+    --chr_fold_path=$fold \
+    --inputlen=$inputlen \
+    --outputlen=$outputlen \
+    --output_prefix=$output_dir/bias \
+    --batch_size=256 \
+    --model_h5=$output_dir/bias_model_scaled.h5 | tee -a $logfile
 
 # marginal footprinting
+
+#path to pwm file
+srcdir=`chrombpnet_srcdir`
+# marginal_footprint_dir=`echo which chrombpnet_marginal_footprints`
+marginal_footprint_dir="$srcdir/evaluation/marginal_footprints"
+echo $marginal_footprint_dir
+
 if [[ "$data_type" = "DNASE_SE" || "$data_type" = "DNASE_PE" ]] ; then
         echo $( timestamp ): "mkdir $output_dir/footprints" | tee -a $logfile
         mkdir $output_dir/footprints
-        echo $( timestamp ): "python $PWD/src/evaluation/marginal_footprints/marginal_footprinting.py \\
+        echo $( timestamp ): "chrombpnet_marginal_footprints \\
         -g $reference_fasta \\
         -r $output_dir/filtered.nonpeaks.bed \\
         --chr_fold_path=$fold \\
         -m $output_dir/chrombpnet_wo_bias.h5 \\
         -bs 512 \\
         -o $output_dir/footprints/corrected \\
-        -pwm_f src/evaluation/marginal_footprints/motif_to_pwm.tsv \\
+        -pwm_f $marginal_footprint_dir/motif_to_pwm.tsv \\
         -mo dnase_1,dnase_2" | tee -a $logfile
-        python $PWD/src/evaluation/marginal_footprints/marginal_footprinting.py \
-        -g $reference_fasta \
-        -r $output_dir/filtered.nonpeaks.bed \
-        --chr_fold_path=$fold \
-        -m $output_dir/chrombpnet_wo_bias.h5 \
-        -bs 512 \
-        -o $output_dir/footprints/corrected \
-        -pwm_f src/evaluation/marginal_footprints/motif_to_pwm.tsv \
-        -mo dnase_1,dnase_2 | tee -a $logfile
+        chrombpnet_marginal_footprints \
+            -g $reference_fasta \
+            -r $output_dir/filtered.nonpeaks.bed \
+            --chr_fold_path=$fold \
+            -m $output_dir/chrombpnet_wo_bias.h5 \
+            -bs 512 \
+            -o $output_dir/footprints/corrected \
+            -pwm_f $marginal_footprint_dir/motif_to_pwm.tsv \
+            -mo dnase_1,dnase_2 | tee -a $logfile
 elif [[ "$data_type" = "ATAC_SE" || "$data_type" = "ATAC_PE"  ]] ; then
         echo $( timestamp ): "mkdir $output_dir/footprints" | tee -a $logfile
         mkdir $output_dir/footprints
-        echo $( timestamp ): "python $PWD/src/evaluation/marginal_footprints/marginal_footprinting.py \\
-        -g $reference_fasta \\
+        echo $( timestamp ): "chrombpnet_marginal_footprints \\
+        -g $reference_fasta \\				     
         -r $output_dir/filtered.nonpeaks.bed \\
         --chr_fold_path=$fold \\
         -m $output_dir/chrombpnet_wo_bias.h5 \\
         -bs 512 \\
         -o $output_dir/footprints/corrected \\
-        -pwm_f src/evaluation/marginal_footprints/motif_to_pwm.tsv \\
+        -pwm_f $marginal_footprint_dir/motif_to_pwm.tsv \\
         -mo tn5_1,tn5_2,tn5_3,tn5_4,tn5_5" | tee -a $logfile
-        python $PWD/src/evaluation/marginal_footprints/marginal_footprinting.py \
-        -g $reference_fasta \
-        -r $output_dir/filtered.nonpeaks.bed \
-        --chr_fold_path=$fold \
-        -m $output_dir/chrombpnet_wo_bias.h5 \
-        -bs 512 \
-        -o $output_dir/footprints/corrected \
-        -pwm_f src/evaluation/marginal_footprints/motif_to_pwm.tsv \
-        -mo tn5_1,tn5_2,tn5_3,tn5_4,tn5_5 | tee -a $logfile
+        chrombpnet_marginal_footprints \
+            -g $reference_fasta \
+            -r $output_dir/filtered.nonpeaks.bed \
+            --chr_fold_path=$fold \
+            -m $output_dir/chrombpnet_wo_bias.h5 \
+            -bs 512 \
+            -o $output_dir/footprints/corrected \
+            -pwm_f $marginal_footprint_dir/motif_to_pwm.tsv \
+            -mo tn5_1,tn5_2,tn5_3,tn5_4,tn5_5 | tee -a $logfile
 else
     echo "ERROR: unknown data type " $data_type | tee -a $logfile
 fi
 
 # marginal footprtining bias model
 if [[ "$data_type" = "DNASE_SE" || "$data_type" = "DNASE_PE" ]] ; then
-        echo $( timestamp ): "mkdir $output_dir/footprints" | tee -a $logfile
-        mkdir $output_dir/footprints
-        echo $( timestamp ): "python $PWD/src/evaluation/marginal_footprints/marginal_footprinting.py \\
+        # echo $( timestamp ): "mkdir $output_dir/footprints" | tee -a $logfile
+        # mkdir $output_dir/footprints
+        echo $( timestamp ): "chrombpnet_marginal_footprints \\
         -g $reference_fasta \\
         -r $output_dir/filtered.nonpeaks.bed \\
         --chr_fold_path=$fold \\
         -m $output_dir/bias_model_scaled.h5 \\
         -bs 512 \\
         -o $output_dir/footprints/bias \\
-        -pwm_f src/evaluation/marginal_footprints/motif_to_pwm.tsv \\
+        -pwm_f $marginal_footprint_dir/motif_to_pwm.tsv \\
         -mo dnase_1,dnase_2" | tee -a $logfile
-        python $PWD/src/evaluation/marginal_footprints/marginal_footprinting.py \
-        -g $reference_fasta \
-        -r $output_dir/filtered.nonpeaks.bed \
-        --chr_fold_path=$fold \
-        -m $output_dir/bias_model_scaled.h5 \
-        -bs 512 \
-        -o $output_dir/footprints/bias \
-        -pwm_f src/evaluation/marginal_footprints/motif_to_pwm.tsv \
-        -mo dnase_1,dnase_2 | tee -a $logfile
+        chrombpnet_marginal_footprints \
+            -g $reference_fasta \
+            -r $output_dir/filtered.nonpeaks.bed \
+            --chr_fold_path=$fold \
+            -m $output_dir/bias_model_scaled.h5 \
+            -bs 512 \
+            -o $output_dir/footprints/bias \
+            -pwm_f $marginal_footprint_dir/motif_to_pwm.tsv \
+            -mo dnase_1,dnase_2 | tee -a $logfile
 elif [[ "$data_type" = "ATAC_SE" || "$data_type" = "ATAC_PE"  ]] ; then
-        echo $( timestamp ): "mkdir $output_dir/footprints" | tee -a $logfile
-        mkdir $output_dir/footprints
-        echo $( timestamp ): "python $PWD/src/evaluation/marginal_footprints/marginal_footprinting.py \\
+        # echo $( timestamp ): "mkdir $output_dir/footprints" | tee -a $logfile
+        # mkdir $output_dir/footprints
+        echo $( timestamp ): "chrombpnet_marginal_footprints \\
         -g $reference_fasta \\
         -r $output_dir/filtered.nonpeaks.bed \\
         -chr "chr1" \\
         -m $output_dir/bias_model_scaled.h5 \\
         -bs 512 \\
         -o $output_dir/footprints/bias \\
-        -pwm_f src/evaluation/marginal_footprints/motif_to_pwm.tsv \\
+        -pwm_f $marginal_footprint_dir/motif_to_pwm.tsv \\
         -mo tn5_1,tn5_2,tn5_3,tn5_4,tn5_5" | tee -a $logfile
-        python $PWD/src/evaluation/marginal_footprints/marginal_footprinting.py \
-        -g $reference_fasta \
-        -r $output_dir/filtered.nonpeaks.bed \
-        --chr_fold_path=$fold \
-        -m $output_dir/bias_model_scaled.h5 \
-        -bs 512 \
-        -o $output_dir/footprints/bias \
-        -pwm_f src/evaluation/marginal_footprints/motif_to_pwm.tsv \
-        -mo tn5_1,tn5_2,tn5_3,tn5_4,tn5_5 | tee -a $logfile
+        chrombpnet_marginal_footprints \
+            -g $reference_fasta \
+            -r $output_dir/filtered.nonpeaks.bed \
+            --chr_fold_path=$fold \
+            -m $output_dir/bias_model_scaled.h5 \
+            -bs 512 \
+            -o $output_dir/footprints/bias \
+            -pwm_f $marginal_footprint_dir/motif_to_pwm.tsv \
+            -mo tn5_1,tn5_2,tn5_3,tn5_4,tn5_5 | tee -a $logfile
 else
     echo "ERROR: unknown data type " $data_type | tee -a $logfile
 fi
diff --git a/step7_interpret_chrombpnet_model.sh b/step7_interpret_chrombpnet_model.sh
old mode 100644
new mode 100755
index 9141b39a..d3ef42ba
--- a/step7_interpret_chrombpnet_model.sh
+++ b/step7_interpret_chrombpnet_model.sh
@@ -1,25 +1,30 @@
+#!/bin/bash
+
+echo "WARNING: If upgrading from v1.0 or v1.1 to v1.2. Note that chrombpnet has undergone linting to generate a modular structure for release on pypi.Hard-coded script paths are no longer necessary. Please refer to the updated README (below) to ensure your script calls are compatible with v1.2"
+
 # exit when any command fails
 set -e
+set -o pipefail
 
 # keep track of the last executed command
 trap 'last_command=$current_command; current_command=$BASH_COMMAND' DEBUG
 # echo an error message before exiting
-trap 'echo "\"${last_command}\" command filed with exit code $?."' EXIT
+trap 'echo "\"${last_command}\" command failed with exit code $?."' EXIT
 
-reference_fasta=$1
-regions=$2
-model_h5=$3
-output_dir=$4
+reference_fasta=${1?param missing - reference_fasta}
+regions=${2?param missing - regions}
+model_h5=${3?param missing - model_h5}
+output_dir=${4?param missing - output_dir}
 
 ## deepshap run
 
-python $PWD/src/evaluation/interpret/interpret.py \
-       --genome=$reference_fasta \
-       --regions=$regions \
-       --output_prefix=$output_dir/corrected \
-       --model_h5=$model_h5 \
+chrombpnet_deepshap \
+    --genome=$reference_fasta \
+    --regions=$regions \
+    --output_prefix=$output_dir/corrected \
+    --model_h5=$model_h5 \
 
 ## modisco run
 
-python src/evaluation/modisco/run_modisco.py -s $output_dir/corrected -p "profile" -o $output_dir -m 50000 -c 500
-python src/evaluation/modisco/run_modisco.py -s $output_dir/corrected -p "counts" -o $output_dir -m 50000 -c 500
+chrombpnet_modisco -s $output_dir/corrected -p "profile" -o $output_dir -m 50000 -c 500
+chrombpnet_modisco -s $output_dir/corrected -p "counts" -o $output_dir -m 50000 -c 500


Test patch:
diff --git a/src/evaluation/variant_effect_prediction/testing.py b/chrombpnet/evaluation/variant_effect_prediction/testing.py
similarity index 100%
rename from src/evaluation/variant_effect_prediction/testing.py
rename to chrombpnet/evaluation/variant_effect_prediction/testing.py
diff --git a/tests/full_workflow.sh b/tests/full_workflow.sh
new file mode 100755
index 00000000..90e8e56e
--- /dev/null
+++ b/tests/full_workflow.sh
@@ -0,0 +1,75 @@
+#!/bin/bash
+
+# exit when any command fails
+set -e
+
+# keep track of the last executed command
+trap 'last_command=$current_command; current_command=$BASH_COMMAND' DEBUG
+
+GPU=${1-0}
+
+#create directory structure for workflow 
+data_dir=data
+mkdir -p $data_dir
+output_dir=outputs
+mkdir -p $output_dir
+output_data=$output_dir/data
+mkdir -p $output_data
+mkdir -p $output_data/subsample_peaks
+output_models=$output_dir/models
+mkdir -p $output_models
+mkdir -p $output_models/bias_model
+mkdir -p $output_models/bias_model/interpret
+mkdir -p $output_models/chrombpnet_model/
+mkdir -p $output_models/chrombpnet_model/interpret
+
+
+step1_download_bams_and_peaks.sh $data_dir
+echo "completed step 1"
+
+
+in_bam=$data_dir/merged.bam
+bigwig_prefix=$data_dir/merged
+data_type=ATAC_PE
+reference_fasta=$data_dir/hg38.fa
+chrom_sizes=$data_dir/hg38.chrom.sizes
+step2_make_bigwigs_from_bams.sh $in_bam $bigwig_prefix $data_type $reference_fasta $chrom_sizes
+echo "completed step 2"
+
+mkdir -p $output_data/splits
+chrombpnet_make_splits -o $output_data/splits
+fold=$output_data/splits/fold_0.json
+echo "made folds"
+
+chrombpnet_genomewide_gc -g $reference_fasta -o $data_dir/genomewide_gc_hg38_stride_1000_inputlen_2114
+echo "got genomewide gc"
+
+blacklist_region=$data_dir/blacklist.bed.gz
+overlap_peak=$data_dir/overlap.bed.gz
+inputlen=2114
+genomewide_gc=$data_dir/genomewide_gc_hg38_stride_1000_inputlen_2114.bed
+step3_get_background_regions.sh $reference_fasta $chrom_sizes $blacklist_region $overlap_peak $inputlen $genomewide_gc $output_data $fold
+echo "completed step 3"
+
+bias_threshold_factor=0.5
+nonpeaks=$output_data/negatives_with_summit.bed
+bigwig_path=$bigwig_prefix\_unstranded.bw
+CUDA_VISIBLE_DEVICES=$GPU step4_train_bias_model.sh $reference_fasta $bigwig_path $overlap_peak $nonpeaks $fold $bias_threshold_factor $output_models/bias_model
+echo "completed step 4"
+
+flank_size=$(( $inputlen/2 ))
+echo $flank_size
+bedtools slop -i $blacklist_region -g $chrom_sizes -b $flank_size > $output_data/subsample_peaks/temp.txt
+bedtools intersect -v -a $overlap_peak -b $output_data/subsample_peaks/temp.txt | shuf  > $output_data/subsample_peaks/temp_n.txt
+shuf -n 30000 $output_data/subsample_peaks/temp_n.txt > $output_data/subsample_peaks/30K.subsample.overlap.bed
+rm  $output_data/subsample_peaks/temp.txt
+rm $output_data/subsample_peaks/temp_n.txt
+
+CUDA_VISIBLE_DEVICES=$GPU step5_interpret_bias_model.sh $reference_fasta $output_data/subsample_peaks/30K.subsample.overlap.bed $output_models/bias_model/bias.h5 $output_models/bias_model/interpret/
+echo "completed step 5"
+
+CUDA_VISIBLE_DEVICES=$GPU step6_train_chrombpnet_model.sh $reference_fasta $bigwig_path $overlap_peak $nonpeaks $fold $output_models/bias_model/bias.h5 $output_models/chrombpnet_model $data_type
+echo "completed step 6" 
+
+CUDA_VISIBLE_DEVICES=$GPU step7_interpret_chrombpnet_model.sh $reference_fasta $output_data/subsample_peaks/30K.subsample.overlap.bed $output_models/chrombpnet_model/chrombpnet_wo_bias.h5 $output_models/chrombpnet_model/interpret/
+echo "completed step 7"