<s> from copy import copy <EOL> import numpy as np <EOL> from . . base import Model , CollectionMixin , ParamMixin <EOL> from . . feed import Feed <EOL> class SiameseNetwork ( Model , CollectionMixin ) : <EOL> def __init__ ( self , siamese_layers , loss ) : <EOL> self . layers = siamese_layers <EOL> self . loss = loss <EOL> self . layers2 = [ copy ( layer ) for layer in self . layers ] <EOL> for layer1 , layer2 in zip ( self . layers , self . layers2 ) : <EOL> if isinstance ( layer1 , ParamMixin ) : <EOL> layer2 . params = [ p . share ( ) for p in layer1 . params ] <EOL> self . bprop_until = next ( ( idx for idx , l in enumerate ( self . layers ) <EOL> if isinstance ( l , ParamMixin ) ) , <NUM_LIT:0> ) <EOL> self . layers [ self . bprop_until ] . bprop_to_x = False <EOL> self . layers2 [ self . bprop_until ] . bprop_to_x = False <EOL> self . collection = self . layers + self . layers2 <EOL> self . _initialized = False <EOL> def setup ( self , x1_shape , x2_shape , y_shape = None ) : <EOL> if self . _initialized : <EOL> return <EOL> next_shape = x1_shape <EOL> for layer in self . layers : <EOL> layer . setup ( next_shape ) <EOL> next_shape = layer . y_shape ( next_shape ) <EOL> next_shape = x2_shape <EOL> for layer in self . layers2 : <EOL> layer . setup ( next_shape ) <EOL> next_shape = layer . y_shape ( next_shape ) <EOL> next_shape = self . loss . y_shape ( next_shape ) <EOL> self . _initialized = True <EOL> def update ( self , x1 , x2 , y ) : <EOL> self . phase = '<STR_LIT:train>' <EOL> for layer in self . layers : <EOL> x1 = layer . fprop ( x1 ) <EOL> for layer in self . layers2 : <EOL> x2 = layer . fprop ( x2 ) <EOL> grad1 , grad2 = self . loss . grad ( y , x1 , x2 ) <EOL> layers = self . layers [ self . bprop_until : ] <EOL> for layer in reversed ( layers [ <NUM_LIT:1> : ] ) : <EOL> grad1 = layer . bprop ( grad1 ) <EOL> layers [ <NUM_LIT:0> ] . bprop ( grad1 ) <EOL> layers2 = self . layers2 [ self . bprop_until : ] <EOL> for layer in reversed ( layers2 [ <NUM_LIT:1> : ] ) : <EOL> grad2 = layer . bprop ( grad2 ) <EOL> layers2 [ <NUM_LIT:0> ] . bprop ( grad2 ) <EOL> return self . loss . loss ( y , x1 , x2 ) <EOL> def embed ( self , feed ) : <EOL> self . phase = '<STR_LIT:test>' <EOL> feed = Feed . from_any ( feed ) <EOL> next_shape = feed . x . shape <EOL> for layer in self . layers : <EOL> next_shape = layer . y_shape ( next_shape ) <EOL> feats = [ ] <EOL> for x , in feed . batches ( ) : <EOL> for layer in self . layers : <EOL> x = layer . fprop ( x ) <EOL> feats . append ( np . array ( x ) ) <EOL> feats = np . concatenate ( feats ) [ : feed . n_samples ] <EOL> return feats <EOL> def distances ( self , feed ) : <EOL> self . phase = '<STR_LIT:test>' <EOL> feed = Feed . from_any ( feed ) <EOL> dists = [ ] <EOL> for x1 , x2 in feed . batches ( ) : <EOL> for layer in self . layers : <EOL> x1 = layer . fprop ( x1 ) <EOL> for layer in self . layers2 : <EOL> x2 = layer . fprop ( x2 ) <EOL> dists . append ( np . ravel ( np . array ( self . loss . fprop ( x1 , x2 ) ) ) ) <EOL> dists = np . concatenate ( dists ) [ : feed . n_samples ] <EOL> return dists </s>
