Package: fastBio
Welcome to fastBiofastBio is a package for manipulating data and creating and training deep learning models for biological sequencing data. It is an extension of the fastai v1 library.A number of pretrained models for biological sequencing data can be loaded directly through fastBio with theLookingGlassandLookingGlassClassifierclasses.
These models are available for download at the sister repositoryLookingGlass.If you find fastBio or LookingGlass useful, please cite the preprint:Hoarfrost, A., Aptekmann, A., Farfanuk, G. & Bromberg, Y. Shedding Light on Microbial Dark Matter with A Universal Language of Life.bioRxiv(2020). doi:10.1101/2020.12.23.424215.https://www.biorxiv.org/content/10.1101/2020.12.23.424215v2.InstallationYou can install fastBio with pip (python 3 only):pip3 install fastBioDocsThe docs for the fastBio package arehere.TutorialYou can run the following tutorial in a jupyter notebook by downloading the notebook inthis repository.importfastBioSteps to training a modelIn fast.ai, there are three basic steps to training a deep learning model:Define yourtransforms(for sequences/text, this means defining thetokenizerandvocabularyyou will use for tokenization and numericalization)Create aDatabunch(which wraps up a Pytorch Dataset and Dataloader into one)Create aLearnerwith your specifiedmodel configand train!If fastai v1 is new to you, I recommend taking a look at their very extensivedocumentation,forum, andonline course. Note fastBio uses fastai v1, which isn't compatible with the new fastai v2.Biological sequence data asks for some special treatment as compared to text (kmer-based tokenization; handling sequence file types like fasta/fastq), so while we can use much of the built-in fast.aitextfunctionality, fastBio provides some helper functions and classes to deal with some of the quirks of biological data.create tokenizer and vocabulary for transforming seq datafromfastBioimportBioTokenizer,BioVocab#define a tokenizer with the correct kmer size and stride for your datatok=BioTokenizer(ksize=1,stride=1)tokBioTokenizer with the following special tokens:
 - xxunk
 - xxpad
 - xxbos
 - xxeosThe kmer size is how many nucleotides constitute a 'word' in the sequence, and the stride is the number of nucleotides to skip between tokens.So for a sequence:ACGGCGCTCa kmer size of 3 and stride of 1 would result in the tokenized sequence:['ACG','CGG','GGC','GCG','CGC','GCT','CTC']whereas a kmer size of 3 and stride of 3 would result in:['ACG','GCG','CTC']create vocab from scratchmodel_voc=BioVocab.create_from_ksize(ksize=1)print(model_voc.itos)model_voc.stoi['xxunk', 'xxpad', 'xxbos', 'xxeos', 'T', 'G', 'C', 'A']





defaultdict(int,
            {'xxunk': 0,
             'xxpad': 1,
             'xxbos': 2,
             'xxeos': 3,
             'T': 4,
             'G': 5,
             'C': 6,
             'A': 7})Above I created a vocabulary using a kmer size of 1 (so just the nucleotides A, C, T, G), but you can use larger kmer sizes as well:model_voc=BioVocab.create_from_ksize(ksize=2)print(model_voc.itos)model_voc.stoi['xxunk', 'xxpad', 'xxbos', 'xxeos', 'CC', 'GA', 'AG', 'CG', 'CT', 'TC', 'TT', 'TG', 'GG', 'GT', 'CA', 'GC', 'AC', 'AT', 'TA', 'AA']





defaultdict(int,
            {'xxunk': 0,
             'xxpad': 1,
             'xxbos': 2,
             'xxeos': 3,
             'CC': 4,
             'GA': 5,
             'AG': 6,
             'CG': 7,
             'CT': 8,
             'TC': 9,
             'TT': 10,
             'TG': 11,
             'GG': 12,
             'GT': 13,
             'CA': 14,
             'GC': 15,
             'AC': 16,
             'AT': 17,
             'TA': 18,
             'AA': 19})Or download the predefined LookingGlass vocabularyFor training the LookingGlass model, I used a ksize=1, stride=1. If you're using a pretrained LookingGlass-based model, you want to make sure that your vocabulary is in the same order so that numericalization is the same for your data as for the LookingGlass weights.Or, it's easy to simply download the LookingGlass vocabulary for this purpose:#or download from pretrained vocab used in LookingGlass#you might need this if you are me...importsslssl._create_default_https_context=ssl._create_unverified_contextimporturllib.requesturllib.request.urlretrieve("https://github.com/ahoarfrost/LookingGlass/releases/download/v1.0/ngs_vocab_k1_withspecial.npy","ngs_vocab_k1_withspecial.npy")importnumpyasnpvoc=np.load('ngs_vocab_k1_withspecial.npy')model_voc=BioVocab(voc)print(model_voc.itos)model_voc.stoi['xxunk' 'xxpad' 'xxbos' 'xxeos' 'G' 'A' 'C' 'T']





defaultdict(int,
            {'xxunk': 0,
             'xxpad': 1,
             'xxbos': 2,
             'xxeos': 3,
             'G': 4,
             'A': 5,
             'C': 6,
             'T': 7})Notice that the order of the nucleotides in the vocabulary is different than the one that we generated from scratch; if you're using the pretrained LookingGlass-based models, make sure you're using the LookingGlass vocab described here as well.create a databunchYou can create a databunch using theBioLMDataBunch(for language modeling) orBioClasDataBunch(for classification). You can do this from raw sequence data fasta/fastq files or csv files:from_folderfrom_seqfilefrom_dffrom_multiple_csvYou will probably want to create aBioLMDataBunchfrom_folder (which will include all sequences from a folder containing multiple fasta/fastq files), or from_seqfile (all sequences from a single fasta or fastq file).For aBioClasDataBunch, I find it easiest in practice to convert sequence files like fasta/fastq to csv files with the label in a column and the sequence in another column, and use from_df or from_multiple_csv, rather than use from_seqfile or from_folder. Alternatively, youcanuse theBioTextListclass to go straight from sequence files.You can create a custom databunch, a la the fast.ai data block API, using theBioTextListclass, which provides a few extra specialized labeling functions etc. If youmustuse sequence files for classification, for example, you can provide a fairly complicated regex-based function to use fastai's label_from_func, or create a BioTextList.from_folder and use label_from_fname or label_from_header in the BioTextList class to extract labels from a filename or fasta header, for instance.BioLMDataBunch exampleHere we'll download some toy metagenomes (a small subset of sequences from 6 marine metagenomes from theTARA project), split them into 'train' and 'valid' folders, and create a BioLMDataBunch:fromfastBioimportBioLMDataBunch#these are 1000 random sequences from 6 marine metagenomes from the TARA project:frompathlibimportPathPath('./lmdata/train').mkdir(parents=True,exist_ok=True)Path('./lmdata/valid').mkdir(parents=True,exist_ok=True)forsrrin['ERR598981','ERR599020','ERR599039','ERR599052']:print('downloading',srr,'...')'https://raw.githubusercontent.com/ahoarfrost/fastBio/master/example_data/TARA_cut1000/'+srr+'_cut1000.fastq'url='https://raw.githubusercontent.com/ahoarfrost/fastBio/master/example_data/TARA_cut1000/'+srr+'_cut1000.fastq'urllib.request.urlretrieve(url,Path('./lmdata/train/'+srr+'_cut1000.fastq'))forsrrin['ERR599063','ERR599115']:print('downloading',srr,'...')url='https://raw.githubusercontent.com/ahoarfrost/fastBio/master/example_data/TARA_cut1000/'+srr+'_cut1000.fastq'urllib.request.urlretrieve(url,Path('./lmdata/valid/'+srr+'_cut1000.fastq'))data_path=Path('./lmdata/')train_path=Path('./train/')#relative to data_pathvalid_path=Path('./valid/')data_outfile=Path('metagenome_LMbunch.pkl')#define your batch size, ksize, and bpttbs=512bptt=100ksize=1max_seqs=None#None or int to optionally limit the number of sequences read from each file in trainingval_max_seqs=None#same for valid setskiprows=0#0 or int to optionally skip X sequences in the beginning of the file before reading into the databunchval_skiprows=0#same for valid set#these will default to the parameters chosen here, we don't technically need to pass them#using tok and model_voc defined above#create new training chunkprint('creating databunch')lmdata=BioLMDataBunch.from_folder(path=data_path,train=train_path,valid=valid_path,ksize=ksize,tokenizer=tok,vocab=model_voc,max_seqs_per_file=max_seqs,val_maxseqs=val_max_seqs,skiprows=skiprows,val_skiprows=val_skiprows,bs=bs,bptt=bptt)print('there are',len(lmdata.items),'items in itemlist, and',len(lmdata.valid_ds.items),'items in lmdata.valid_ds')print('databunch preview:')print(lmdata)#you can save your databunch to file like so:lmdata.save(data_outfile)there are 4000 items in itemlist, and 2000 items in lmdata.valid_ds
databunch preview:
BioLMDataBunch;

Train: LabelList (4000 items)
x: BioLMTextList
xxbos A T T A A A G A T A T C A A T G C G T A A A T C T T T A T T C T T A A T A T T A A T A T C T T A T T C A T T A T C A A T A T T T A G T T T T G A A T T T A G T G T T A T G A C C C T A A A T G C T C A A A,xxbos T G C T T T A A T T C G A T G G G T A A A T A A G C C T xxunk A T C A T T C T T T T T T G G G T C A T C A A T C G T A T C A A,xxbos T G T T A A A G C A A T A G G C A G T G A A G C A G A A G G C A G T C T C A C T G G A G T G C A C A C A G G T T T A A T G G G T T T G G G T T T C A T T A T A G G C A C G A T A A G C A T T G G A T T T G,xxbos T T T A T G T C C C T G G C T G C C A T G A A A C G G T xxunk T A C A A C A A A A G G C T G T C C C G G A T A G C C A A A T C,xxbos C C A T T A G A G T T T G T T G T T G A G T A A G T A T A A G C T C C T G A A C T T G T A T A A G T T G T T C C A T T C C A A C T A T A A G A A T C A C A A G A A G T A T G T G T A G T T G C A G A T G T
y: LMLabelList
,,,,
Path: /Users/adrienne/Projects/fastBio/lmdata/train;

Valid: LabelList (2000 items)
x: BioLMTextList
xxbos A T T T T A A A G C A T A T G G T A G T A A A G G T A T T T C T T C C A A T A A A C T A C T T A G T C T G G G G A T T A A A G A T T T T C A C C G A A G T T T C C G A A T T G A A A A C A T T T C T C A A,xxbos T T T T C T T G A C T A T T T C C T T G G G C T C C A A C C A A A T A G G G G G C G A G C T T G G C G T A G G T G T T T T G A G A A A T G T T T T C A A T T C G G A A A C T T C G G T G A A A A T C T T T,xxbos T G C A A A A T C T T A T A C T A A A A T T G G T G A A A A T G T A A A A G A A G G C A T C T T T T T A C A T T A A A C T A A A A G A C G T G T T A A A C T A T T G A A A G A A G A A T T A A A A A A A,xxbos T A T T T T A T A T T C T A T A T C T T T T A C A T G T A T A G T T T C A T C T T T T C C T T T G T A A G T A A A C T T A A T A A T A C T A T G T T T T T T T A A T T C T T C T T T C A A T A G T T T A A,xxbos C T A G A C T T T T T T A T T C C T A A T T T C A A T T T T T C A T A T T T A T C T G A T G C T A G A T T T T T T A A A T C A T T A
y: LMLabelList
,,,,
Path: /Users/adrienne/Projects/fastBio/lmdata/valid;

Test: NoneBioClasDataBunch exampleHere we'll download sequences that I've preprocessed: downloading the coding sequences of three genomes, splitting them into read-length chunks, and recording that sequence, along with the label of the known reading frame from the coding sequence, in a csv file for each sequence. The sequence is in a column named 'seq' and the label is in a column named 'frame'.We'll split these csv files into train and valid folders and create a BioClasDataBunch from_multiple_csvfromfastBioimportBioClasDataBunchfrompathlibimportPathPath('./clasdata/train').mkdir(parents=True,exist_ok=True)Path('./clasdata/valid').mkdir(parents=True,exist_ok=True)forgenomein['GCA_000007025.1_ASM702v1','GCA_000008685.2_ASM868v2']:print('downloading',genome,'...')url='https://github.com/ahoarfrost/fastBio/raw/master/example_data/FrameClas_sample/'+genome+'.csv'urllib.request.urlretrieve(url,Path('./clasdata/train/'+genome+'.csv'))url='https://github.com/ahoarfrost/fastBio/raw/master/example_data/FrameClas_sample/GCA_000011445.1_ASM1144v1.csv'print('downloading GCA_000011445.1_ASM1144v1...')urllib.request.urlretrieve(url,Path('./clasdata/valid/GCA_000011445.1_ASM1144v1.csv'))data_path=Path('./clasdata/')train_path=Path('./clasdata/train/')valid_path=Path('./clasdata/valid/')data_outfile=Path('frameclas_bunch.pkl')#use tok and model_voc defined above again#you can optionally limit the number of sequences you read (and how many rows to skip in the csv)framedata=BioClasDataBunch.from_multiple_csv(path=data_path,train=train_path,valid=valid_path,text_cols='seq',label_cols='frame',tokenizer=tok,vocab=model_voc,#let's limit the number of sequences for this toy examplemax_seqs_per_file=1000,valid_max_seqs=500,skiprows=0,bs=512)print('there are',len(framedata.items),'items in itemlist, and',len(framedata.valid_ds.items),'items in data.valid_ds')print('there are',framedata.c,'classes')print('databunch preview:')print(framedata)#you can save your databunch to file like so:framedata.save(data_outfile)there are 2000 items in itemlist, and 500 items in data.valid_ds
there are 6 classes
databunch preview:
TextClasDataBunch;

Train: LabelList (2000 items)
x: BioTextList
xxbos A G T T A A A T C G A T T T G G G T T C C A A T A A A A A A T T T T A T A G C A A G T G T A T C A G T T A A A A T T G A A T A C T T G G T A A T G T A A A T A G T G A A A G C T A A A T T G A A A T A,xxbos A A A G A A G T C G A T A A T T T A T A G T A A A T A C T A T A G T T A T T A G G T A T G A A A T C A A T T T C A A A T T T G A A G G T A A T T A T G G G A A G A A T T G G A T A G A G A A A T G C A T G A G T T G T T T T T C C T G T A A A T A T A G T A G T T C T C A G,xxbos A A T G A A G T A T A G T G C T A T T T T A T T A A T A T G T A G C G T T A A T T T A T T T T G T T T T C A A A A T A A A T T A A C T A C T T C T C G A T G G G A A T T C C C T A A A G A A G A T T T A A T T A A A A A A A A A A T A A A A A T A G G C A T A A T T T A C C A T A A T T A C A T A A A T T C T A T C T T T T A C A A T G A A A A T T A T A A A T A C A T T G C C T T T A T C G G A A T A T T G A C A T C T T A T A A T G A A T G G A T T G A A A T A C A A T T T A G C C C C A T A A A T T T T T T T A C T A T C C C A A C A A A T A A A G A T T T T A T T T C A A A T A C T,xxbos C T A A T A T T G A A A A T G C T A T T A A A A A G T C T T T G A G T T C G G G T G T C A A T A T A G T A C T C A T T C C T T A G,xxbos T T G C A T C T T A T T T A T A A A A T T G G T G A A G T T C T T G C T A A A C A A T T G C G T A G A T T G G G T A T T A A T T T A A A T A T G G C T C C A G T T G C C G A T A T A A A A T T T G C A C C A C A T A C T C C T T T A T T A A A T A G G A C A T T T G G A G G A T A T T C C G C T T A T A A T
y: CategoryList
-1,-1,2,3,1
Path: /Users/adrienne/Projects/fastBio/clasdata;

Valid: LabelList (500 items)
x: BioTextList
xxbos A T C T C T A C C A C C A A A T T C T T C T C C A A T T T G A G C T A A A G T G T G A T T T A A G A T C T C T T T T G T T A A A A A C A T T G C T A T A T G T C T T G C T G T T A C A A T T G A C T T A,xxbos A A G C T T T T A T A G C A G T T C A A A C C G T A A G T A A A A A T C C T G G A A T T T C T T A T A A T C C A T T G T T T A T T T A T G G T G A A T C T G G A A T G G G A A A A A C T C A T T T A T T A A A A G C T G C A A A A A A C T A T A T T G A A T C T A A T T T T T C T G A T C T A A A A G T T A,xxbos G T T C A T T A C T T G C A C C G A T T A C A A A A T T T T C A A A T G T G T T T T C A T T A A T T T T T T T A A C T T T T T T A G T G A T G A T A T C A G A A T G A T C T T T T T T G A T T A A T T C A T C T T T T T C T A G T T G T T T T T T A T A T T C T T G T T C G T A T G T A A A A C T A A T A T T,xxbos T T T A A A A T A C C T A A T T T T G A A G T A G G T A T A T C T C T A A A C A G A T C A G A A A C T A T T T C T A T A G T A A T A A T T T T T T C T T C T G G A T T T T G T T G A G A T C A A A A G T T T A A T C T T G A A A C A C T T C C T T T A A T T T T T C T A A C A T C A T C T G A A T A A T A A,xxbos T G T T A A A A A A A T T A A A G A A G T T G T T A G T G A A A A A T A T G G T A T T T C A G T T A A T G C A A T T G A T G G A A A A G C T A G A A G
y: CategoryList
-2,3,-1,-2,2
Path: /Users/adrienne/Projects/fastBio/clasdata;

Test: Nonecreate a learner and trainYou can now create a fastai 'learner' with your databunch and train!There's nothing special in fastBio youneedto create a learner - you can use get_language_model or get_text_classifier and any model config you want (see the fastai and pytorch docs for this).To use LookingGlass architecture (with or without pretrained weights), use theLookingGlassorLookingGlassClassifierclasses which maintain the architecture used for the LookingGlass models and associated transfer learning tasks.There are several pretrained models available through theLookingGlassrelease, which can be loaded by name in the LookingGlass and LookingGlassClassifier classes.Make sure to use pretrained=False if you're not using a pretrained model (pretrained=True by default).Language modelLet's use our BioLMDataBunch to train a language model with the same architecture as LookingGlass:fromfastBioimportLookingGlassfrom scratch (no pretrained weights)lmlearn=LookingGlass(data=lmdata).load(pretrained=False)#adjusting batch size down for my laptoplmlearn.data.batch_size=64lmlearn.fit_one_cycle(5)epochtrain_lossvalid_lossaccuracytime01.5923601.4514390.30254006:3511.4608931.4117530.31021706:5821.4216471.4029590.31692007:0431.4075781.3997950.32919406:5341.4034321.3993760.33012106:51using a pretrained modelUsing pretrained=True with LookingGlass.load() will load the 'LookingGlass' language model pretrained weights.#create LookingGlass() model from databunch defined abovelmlearn2=LookingGlass(data=lmdata).load(pretrained=True,pretrained_dir='models')downloading pretrained model to models/LookingGlass.pth
loading pretrained LookingGlass language modelClassifierLet's use our BioClasDataBunch to create and train a classifier with the same encoder architecture as LookingGlass to predict the reading frame of a DNA sequence.LookingGlassClassifier has two ways to load a model:load()load_encoder()If using pretrained=False, load() and load_encoder() both create the same classifier with a LookingGlass-like encoder and classification decoder.If using pretrained=True,loadandload_encoderdiffer in the pretrained models that can be loaded:load_encoder - 'LookingGlass_enc' (default), or 'FunctionalClassifier_enc'load - 'FunctionalClassifier', 'OxidoreductaseClassifier', 'OptimalTempClassifier', or 'ReadingFrameClassifier'These models are described in thepreprint.fromfastBioimportLookingGlassClassifierfrom scratch (no pretrained weights)framelearn=LookingGlassClassifier(data=framedata).load(pretrained=False)#decrease batch size for my laptopframelearn.data.batch_size=128framelearn.fit_one_cycle(5)epochtrain_lossvalid_lossaccuracytime01.8376101.7932750.16200003:5211.7694721.7821070.18400003:3921.6883731.7767590.17200003:2431.6315521.6205920.27000003:2441.6003251.5559670.29400003:22We have pretty limited data here, so we don't get great performance. Let's try loading the pretrained LookingGlass encoder and see if we can fine tune it to do any better:with the pretrained 'LookingGlass' encoderframelearn2=LookingGlassClassifier(data=framedata).load_encoder(pretrained_name='LookingGlass_enc',pretrained=True,pretrained_dir='models')downloading pretrained model to models/LookingGlass_enc.pth
loading classifier with pretrained encoder from models/LookingGlass_enc.pth#decrease batch size for my laptopframelearn2.data.batch_size=128framelearn2.fit_one_cycle(5)epochtrain_lossvalid_lossaccuracytime01.8216471.7944910.23800001:1111.6553921.7454290.28000001:1321.4703211.6128990.37600001:1331.3284481.4325600.52800001:1141.2411351.2509880.54800001:11We do much better, but of course we still don't have much data (and we're not using our tricks like gradual training of layers) so our performance isn't yet amazing, and we're starting to overfit.Luckily, there's an existing pretrained model for exactly this classification task, the 'ReadingFrameClassifier', that we can use:using the pretrained ReadingFrameClassifier modelframelearn3=LookingGlassClassifier(data=framedata).load(pretrained_name='ReadingFrameClassifier',pretrained=True,pretrained_dir='models')downloading pretrained model to models/ReadingFrameClassifier.pth
loading pretrained classifier from models/ReadingFrameClassifier.pth#decrease batch size for my laptopframelearn3.data.batch_size=128framelearn3.fit_one_cycle(1)epochtrain_lossvalid_lossaccuracytime00.0609260.1892410.94400001:19much better! Although we're already pretty overfit, so we probably should have just gone straight into using the pretrained model for inference rather than further training.We can do that with framelearn3.predict() or .pred_batch(), or we can load an exported model for inference like so:I don't want to deal with all the databunch/training stuff. What if I really just want to make  a handful of predictions on some data with a pretrained model?You can do that! Pretrained models for LookingGlass and associated transfer learning tasks can be downloaded inrelease v1 of LookingGlass. The ones that end in 'export.pkl' were saved using the fastai 'export' function and can be loaded (with empty databunches) with the fastai load_learner function and used for inference directly:#download the pretrained oxidoreductase classifier to 'models' folderimporturllib.requesturllib.request.urlretrieve('https://github.com/ahoarfrost/LookingGlass/releases/download/v1.0/OxidoreductaseClassifier_export.pkl','models/OxidoreductaseClassifier_export.pkl')('models/OxidoreductaseClassifier_export.pkl',
 <http.client.HTTPMessage at 0x7ffd52420ef0>)#load the model (with an empty databunch)fromfastai.textimportload_learneroxido=load_learner(Path('./models').resolve(),'OxidoreductaseClassifier_export.pkl')Now let's make some predictions for reads in one of our toy metagenomes we downloaded earlier:fromBioimportSeqIOforix,recordinenumerate(SeqIO.parse('lmdata/valid/ERR599115_cut1000.fastq','fastq')):seq=str(record.seq)ifix<20:print('sequence:',seq)print('prediction:',oxido.predict(seq))print('---------')else:breaksequence: GGGTTGCCAGGTCGACGAGCACGACGACGGCTCGAAGAGCGGTTGGTGCGAGGACGGCACCGGTTGGTGG
prediction: (Category nonec1, tensor(1), tensor([0.0130, 0.9870]))
---------
sequence: CTGGTTCCATCATCGTAGGAGTCGGTGGAACAGCCAGTCTCCTCGTCGTAGCTGTAGACGGGCGGAGCCCAGGACTCCTGCACACCCTCGGCGTCCTCC
prediction: (Category nonec1, tensor(1), tensor([0.0024, 0.9976]))
---------
sequence: TTCAGAATAATCAACTCCATCAATATCCCAGCCACATCCTGATAAATATTGACATTGATCATCCGCATAACCCACGCCTAAATACATGTCACACCAGCC
prediction: (Category nonec1, tensor(1), tensor([0.4787, 0.5213]))
---------
sequence: TGGANAGACGCCTATTTGGGTTGCAGAGTGTCCTGAAAATGGTGATTGCATGGATTTGACTGGATTATTTTTTGGCTGGTGTGACATGTATTTAGGCG
prediction: (Category nonec1, tensor(1), tensor([0.0030, 0.9970]))
---------
sequence: ATGATTTAGCAACCATTTTAATCCCCCCTTCAAGTGGGGTTCAATCCGCTGAAGGAGCTCAGCTGGGAACAT
prediction: (Category nonec1, tensor(1), tensor([0.0132, 0.9868]))
---------
sequence: TGTCACTGGCAGCTTATTTAGTGTTCTCTTGTGCAGGACAGAAAGTTCCTGATAATCCAAAACTGGTAGTGATGATAGCCGGCGATATGTTC
prediction: (Category nonec1, tensor(1), tensor([0.0019, 0.9981]))
---------
sequence: TCTGCTGTGCCAGACCGATAAACGAATTCATGATACCAATGACGGTACCGAACAGACCGATATAGCGCGTTACTGAACCTACTGTGGCCAGAAAC
prediction: (Category nonec1, tensor(1), tensor([3.6912e-04, 9.9963e-01]))
---------
sequence: CATCATGGCCGGTTCCCAGCGTGCCATGCGCGTAGCCTATTCGCGTGAAGAGGAAAAGCTGGAAAAACATCTGCCGTTTCTGGCCACAGTAGGTTCAGTA
prediction: (Category ec1, tensor(0), tensor([0.7161, 0.2839]))
---------
sequence: TTATGGAGCATACCAAACATTACCAAATATACGAAAACAAAATTTTGCTATTTTGGTAGAAGGACAAACTGATTGTCTTCGTTTGGTAGAAAATGGTTT
prediction: (Category nonec1, tensor(1), tensor([0.0411, 0.9589]))
---------
sequence: TTTTTAAGCACAGTAGCGTGTTTGCTCGAAAATGCGGTTCCTGAGGTAGCAATTACATTAGAAAAACCATTTTCTACCAAACGAAGACAATCAGTTTGTC
prediction: (Category nonec1, tensor(1), tensor([0.2211, 0.7789]))
---------
sequence: CAGTGACAAGATAATTTTTTCATCGGTATGTTTTATTTATCACTATTTTTCTATCATAGTAATAGTTATCCACACCGCACTAGAACTGCTTTAAATGTT
prediction: (Category nonec1, tensor(1), tensor([0.0069, 0.9931]))
---------
sequence: TAGGTTGTACTTTGAGTCTGTAAGTGAATCGAAAGTGAATCAAAACGTGAACATTTAAAGCAGTTCTAGTGCGGTGTGGATAACTATTACTATGATAGAAA
prediction: (Category nonec1, tensor(1), tensor([0.0203, 0.9797]))
---------
sequence: GCCATGGGCGTTATTTGTCTAATTTGCCCTTTGATGCATCCACGAAGCGGGGTCATCCGTATCCCGGCATCGGTTCTTAACCAGCAAAGGAAGAACAAA
prediction: (Category ec1, tensor(0), tensor([0.6001, 0.3999]))
---------
sequence: AGCCAGCGTGCACCATCAAGGCGCTTTGCTATCGTATTTTCCGGGGCACCATCATTAATATCTCTCGTCTCTTTGTACTTCCTTTGCTGGTTAAGAACCGA
prediction: (Category nonec1, tensor(1), tensor([0.0165, 0.9835]))
---------
sequence: TCTTTTGCTTATTGTTGGTTCAACACAACGTGCACTTTCAGATGGTTCAAAAGTTAGAGGAGACATAAACGTTTTTCTTGTTGGAGATCCTGGTACGGC
prediction: (Category nonec1, tensor(1), tensor([0.2953, 0.7047]))
---------
sequence: CCTGATGTGTATAATCCTCTAGGAGCAATTCTTGAACAGAACTTTAACATTTCACTTTTTGCCGTACCAGGATCTCCAACAAGAAAAACGTTTATGTCTCC
prediction: (Category nonec1, tensor(1), tensor([0.4585, 0.5415]))
---------
sequence: TGCTTACATCAGTCATTTTTTTCACCAAATTCTTCGAGAATCTTAACTGGCCTTATCCGGTCTAAAGTCTT
prediction: (Category ec1, tensor(0), tensor([0.5849, 0.4151]))
---------
sequence: TGATTTCGGTAGCGGATATCCATCTGATAAAAAAACAATTAATTTTTTGAAGAGGTTCTATGCTGATAATGGAAAGTGGCCTGAGGG
prediction: (Category nonec1, tensor(1), tensor([0.1965, 0.8035]))
---------
sequence: AAAACTTTTCTAAAAAATCAATATCTACAATTAAAGAAGCAAGAATCCTAGATGGTGATTCCACATATTTTCTGAATTTTAATCATCAAGAAATTCAAA
prediction: (Category nonec1, tensor(1), tensor([0.1708, 0.8292]))
---------
sequence: AAAGNTTTTTTTTGATTAAATGGTTTGGAATTAAATATCCTAAATTTTCTTTTTGAATTTCTTGATGATTAAAATTCAGAAAATATGTGGAATCACCATCT
prediction: (Category nonec1, tensor(1), tensor([0.0047, 0.9953]))
---------This model predicts whether a sequence comes from an oxidoreductase (EC 1.-.-.-) or not - 'ec1' or 'nonec1'. 3 out of 20 of the sequences are predicted as ec1, which is consistent with the results fromthe paperwhich found around 20% of sequences to be oxidoreductases in marine metagenomes.