#!/usr/bin/python

import numpy as np
import sys
import os
import pysam
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
from pymethyl import MethIndex
import cPickle

motifIndex = {'+':{'CG':1,'CHG':2,'CHH':3}, '-':{'CG':4,'CHG':5,'CHH':6}}
methTypes = ('CG','CHG','CHH')

class methExperiment:
	def __init__(self):
		self.samples = {}
		self.gff = {}
		self.fa = "Unset"
		self.emissions = {}
		self.windowSize = 500.0
	def addSample(self, name, samples = []):
		self.samples[name] = []
		print "Added sample: %s" % (name)
		for i in samples: self.addReplicate(name, i)
	def addReplicate(self,name,replicate):
		if not checkFiles([replicate]):
			self.samples[name].append(replicate)
			print "Added %s to %s" % (replicate, name)
	def addGFF(self, name, gffFile):
		#psedudogene,chromosome,gene,transposable_element,rest is NC
		if not checkFiles([gffFile]):
			if gffFile not in self.gff:
				self.gff[gffFile] = name
		else:
			return 1
	def setReference(self, fa):
		if not checkFiles([fa]):
			self.fa = fa
			self.FA = pysam.Fastafile(self.fa)
	def printExperiment(self): # prints the experiment layout
		print "\nGFF Files:"
		for i in range(len(self.gff)-1):
			k = self.gff.keys()[i]
			print "  |-  [ %s ]\t %s" % (self.gff[k], k)
		k = self.gff.keys()[-1]
		print "   -  [ %s ]\t %s" % (self.gff[k], k)
		print "\nReference: %s\n" % (self.fa)
		for sample in self.samples:
			print "%s:" % (sample)
			numReps = len(self.samples[sample])
			for i in range(numReps-1):
				print "  |- %s" % (self.samples[sample][i])
			print "   - %s\n" % (self.samples[sample][numReps-1])
	def makeMethBins(self, minRegionLen = 700): # creates a dictinary of methylation frequencies per feature
		print "Making methylation bins"
		self.dataDict = {}
		for sampleName in self.samples:
			self.dataDict[sampleName] = {}
			methIndexes = []
			for mf in self.samples[sampleName]:
				methIndexes.append(MethIndex(mf,self.fa))
			for gffFile in self.gff:
				self.dataDict[sampleName][gffFile] = {}
				for methType in methTypes:
					self.dataDict[sampleName][gffFile][methType] = []
				count = 0
				for struct in gff_gen(gffFile, minRegionLen):
					count += 1
					methylBins = geneBin(struct, self.FA, methIndexes)
					for i in range(3):
						methType = methTypes[i]
						if np.isfinite(methylBins[i]):
							self.dataDict[sampleName][gffFile][methType].append(methylBins[i])
				print "%s: %i" % (gffFile,count)
	def plotMethBins(self,outputType='eps'): # prints the frequencies by type from makeMethBins as boxplots
		for sampleName in self.samples:
			fig = plt.figure(figsize=(11,7))
			count = 1
			for methType in methTypes:
				dataList = []
				names = []
				for gff in self.gff:
					dataList.append(self.dataDict[sampleName][gff][methType])
					names.append(self.gff[gff])
				makeBoxplot("31"+str(count), dataList, methType, names, fig)
				count += 1
			plt.xticks(range(len(names)+1)[1:],names)
			plt.subplots_adjust(hspace=0.1, top=0.95, bottom=0.05, left=0.07, right=0.96)
			plt.suptitle("Methylation Probabilities by Region")
			plt.savefig(sampleName+"_probabilities."+outputType)
	def makeEmissions(self): # generate emission probabilies from makeMethBins
		for sampleName in self.samples:
			self.emissions[sampleName] = {}
			for gff in self.gff:
				self.emissions[sampleName][gff] = {}
				print gff
				for methType in methTypes:
					Data = self.dataDict[sampleName][gff][methType]
					hist, edges = np.histogram(Data, bins=10, range=(0,1)) # edges are half open [0, 1)
					self.emissions[sampleName][gff][methType] = hist
		cPickle.dump(self.emissions, open("emissions.pickle",'wb'))
	def readEmissions(self):
		if not checkFiles(['emissions.pickle']):
			# loads self.emissions[sampleName][gff][methType] array of 10 hist values.
			self.emissions = cPickle.load(open("emissions.pickle",'rb'))
		else:
			print "Make emissions first"
	def printEmissions(self):
		print "\nEmission Probabilities"
		for sampleName in self.samples:
			for gff in self.gff:
				print gff
				for methType in methTypes:
					string = "%s:\t" % (methType)
					hist = self.emissions[sampleName][gff][methType]
					for i in hist:
						string += "%d\t" % (i)
					print string + "sum: %d" % (sum(hist))
		print "[0\t"+")\t".join(map(str,np.arange(0.1,1.1,0.1)))+']'
	def makeTransitions(self): # makes transition probabilities
		gffStats = {}
		print "\nGFF Stats:"
		for gffFile in self.gff:
			if self.gff[gffFile] != "NC":
				gffStats[gffFile] = simpleStats(gffFile)
		self.transMatrix = makeTransMatrix(gffStats, self.gff, self.fa+'.fai', self.windowSize)

def getChromSizes(inFai): # returns a dicationary of chromosome sizes
	chromLens = {}
	for line in open(inFai,'r'):	#Chr1	30427671	6	79	80
		tmp = line.split('\t')
		chromLens[tmp[0]] = int(tmp[1])
	return chromLens

def simpleStats(inFile): # returns the count and average size of a feature type
	print inFile
	count = 0
	total = 0
	for line in open(inFile,'r'):
		#Chr1	TAIR10	transposable_element	11897	11976
		count += 1
		tmp = line.split('\t')
		start = int(tmp[3])
		end = int(tmp[4])
		total += end-start+1
	print "\tOccurrences: %d" % (count)
	print "\tAverage Size: %.1f" % (total/float(count))
	return (count, total/float(count))

def makeTransMatrix(gffStats, gff, inFai, windowSize): #generate transition probabilities
	chromSizes = getChromSizes(inFai)
	genomeBases = sum(chromSizes.values())
	#self.gff[gffFile] = name
	#NC	TG	G	PG	TE
	letterIndex = gff.values()
	NC, G, TE = map(letterIndex.index, ["NC","G","TE"])
	transMatrix = np.zeros((5,5))
	basesNC = genomeBases-np.sum(map(lambda x: x[0]*x[1], gffStats.values()))
	windowsNC = basesNC/windowSize
	regionCounts = sum(map(lambda x: x[0], gffStats.values()))
	transMatrix[NC][NC] = windowsNC/float(windowsNC+regionCounts)
	te2gene = 4178.0/31189.0 #make this dynamic
	gene2te = 4178.0/28775.0 #make this dynamic
	for gffFile,v in gffStats.iteritems():
		curLetter = gff[gffFile]
		curIndex = letterIndex.index(curLetter)
		count, avg = v
		windowsPerRegion = avg/windowSize
		toRegion = count/float(windowsNC+regionCounts)
		transMatrix[NC][curIndex] = toRegion
		if curLetter == "G":
			stayProb = 1.0/windowsPerRegion
			leaveProb = 1-(gene2te+stayProb)
			transMatrix[curIndex][TE] = gene2te
		elif curLetter == "TE":
			stayProb = 1.0/windowsPerRegion
			leaveProb = 1-(te2gene+stayProb)
			transMatrix[curIndex][G] = te2gene
		else:
			stayProb = 1.0/windowsPerRegion
			leaveProb = (1.0-stayProb)
		transMatrix[curIndex][NC] = leaveProb
		transMatrix[curIndex][curIndex] = stayProb
	print "\nTransition Matrix"
	print "\t"+'\t'.join(letterIndex)+'\tSum'
	for i in range(len(letterIndex)):
		print letterIndex[i]+'\t'+'\t'.join(map(lambda x: str(round(x,2)), transMatrix[i]))+'\t'+str(round(sum(transMatrix[i]),2))
	return transMatrix

def checkFiles(fileList): # check to see if any files in a list don't exist
	if not fileList: return 0
	ret = 0
	for f in fileList:
		if not os.path.isfile(f):
			ret = 1
			print "Could not find: %s" % (f)
	return ret

def geneBin(geneStruct, FA, methReps):
	gChr, gStrand, gStart, gEnd, gID = geneStruct
	geneLen = gEnd-gStart+1
	Y = np.zeros((3,geneLen))			#methyl values
	C = np.zeros((3,geneLen))			#count values
	for rep in methReps:
		methA, contA = rep.fetch(chrom=gChr,start=gStart,end=gEnd)
		methNA = np.array(methA)
		contNA = np.array(contA) #make np for slicing
		rNot1 = methNA != -1
		for methIndex in range(1,len(methTypes)+1): #1-indexed
			for i in range(0,4,3): #handle both strands
				methUse = contNA == methIndex+i
				locUse = np.logical_and(rNot1, methUse)
				C[methIndex-1, locUse] += 1
				Y[methIndex-1, locUse] += methNA[locUse]
			#if gStrand == '+':
			#	methUse = contNA == methIndex+3
			#else:
			#	methUse = contNA == methIndex
			#locUse = np.logical_and(rNot1, methUse)
			#C[methIndex-1, locUse] += 1
			#Y[methIndex-1, locUse] += methNA[locUse]
	outBins = []
	for i in range(3):
		cgt1 = C[i,:] > 1
		Y[i,cgt1] = Y[i,cgt1]/C[i,cgt1] #average across replicates
		outBins.append(meanFunc(Y[i,:],C[i,:]))
	return outBins #(CG, CHG, CHH)

def meanFunc(Y,C): # returns the means of bins
	gZero = Y[C > 0]
	if len(gZero): return np.mean(gZero)
	return np.nan

def gff_gen(inFile, minSize):
	#Chr1    TAIR10  transposable_element_gene       433031  433819  .       -       .       ID=AT1G02228;Note=transposable_element_gene;Name=AT1G02228;Derives_from=AT1TE01405
	IF = open(inFile,'r')
	for line in IF:
		tmp = line.split('\t')
		chrom = tmp[0]
		strand = tmp[6]
		start, end = map(int, tmp[3:5])
		idNum = tmp[8].split(';')[0]
		idNum = idNum.split('=')[1]
		if end-start > minSize:
			yield (chrom, strand, start, end, idNum)
	IF.close()

def makeBoxplot(sp, dataList, methType, names, fig):
	ax = fig.add_subplot(int(sp))
	ax.boxplot(dataList, sym='')
	ax.set_ylabel(methType)
	if sp != "313":
		plt.setp(ax.get_xticklabels(), visible=False)
		plt.setp(ax.get_xticklines(), visible=False)


from utils.logger import create_logger
from utils.parser import parse_arguments
import wave
import logging
import collections
import pyaudio
import struct
import datetime
import os
import numpy as np

# Buffer size in sec (pre recording)
RECORD_BUFFER_SIZE = 3

# Decay time, post record in sec
DECAY_TIME = 3

# Threshold when amplitude is high (% of max amplitude)
RECORD_THRESHOLD = 0.015

# output dir:
OUTPUT_PATH = "output"

def save_recording(pyaudio_obj, channels, format, rate, data):
    # create output path
    os.makedirs(OUTPUT_PATH, exist_ok=True)
    # filename
    filename = os.path.join(OUTPUT_PATH, datetime.datetime.now().replace(
        microsecond=0).isoformat() + ".wav")
    with wave.open(filename, 'wb') as wf:
        wf.setnchannels(channels)
        wf.setsampwidth(pyaudio_obj.get_sample_size(format))
        wf.setframerate(rate)
        wf.writeframes(b''.join(data))
        wf.close()
        logger.info("Written file %s" % filename)

def main(args):
    # Audio chunk, samples per frame
    CHUNK = args.CHUNK_SIZE
    # sample format
    FORMAT = pyaudio.paInt16
    y_range = 2**16
    # Mono
    CHANNELS = 1
    # samples per secound
    RATE = args.SAMPLE_RATE
    # pyaudio object
    p = pyaudio.PyAudio()
    stream = p.open(
        format=FORMAT,
        channels=CHANNELS,
        rate=RATE,
        input=True,
        output=True,
        frames_per_buffer=CHUNK
    )

    # preRecord Buffer - Ring buffer
    pre_record_buf = collections.deque(
        maxlen=int(RATE/CHUNK * RECORD_BUFFER_SIZE))

    # pre record buffer - for visualization (filled with ints not byte data)
    pre_record_buf_int = collections.deque(
        maxlen=int(RATE * RECORD_BUFFER_SIZE))
    # fill with zeros
    for _ in range(pre_record_buf_int.maxlen):
        pre_record_buf_int.append(0)

    # preprocess absolute amplitude threshold
    recording_amplitude_limit = (y_range / 2) * RECORD_THRESHOLD

    # colddown chunks, numberof chunks after last activation before stopping recording.
    decay_chunks = DECAY_TIME * RATE/CHUNK

    # recording flag
    is_recording = False

    # recorded_data, holding recorded data before writing in to file.
    recorded_data = []

    # record counter
    counter = decay_chunks

    # Visualization
    if args.plot:
        fig, ax = plt.subplots()
        # length of x axis
        x = np.arange(0, pre_record_buf_int.maxlen, 1)
        line, = ax.plot(x, np.random.randint(-y_range *
                                             0.55, y_range*0.55, pre_record_buf_int.maxlen))
        plt.show(block=False)

    # Main loop
    while True:
        # Read microfone
        # raw (bytes)
        new_data = stream.read(CHUNK)
        # as int
        new_data_int = struct.unpack(str(CHUNK) + 'h', new_data)

        # decide to start to record
        mean = np.mean(np.abs(new_data_int))
        if mean > recording_amplitude_limit:
            logger.debug("recording amplitude reached")
            counter = decay_chunks
            if not is_recording:
                logger.info("Start new recording")
                recorded_data = []
                is_recording = True
                for sample in pre_record_buf:
                    recorded_data.append(sample)

        # append new data to recording
        if is_recording:
            logger.info("recording... chunks to go %i" % counter)
            counter -= 1
            recorded_data.append(new_data)
            if counter <= 0:
                logger.info("done recording")
                is_recording = False
                save_recording(p, CHANNELS, FORMAT, RATE, recorded_data)

        # append new data pre record buffer
        pre_record_buf.append(new_data)

        # visualization
        if args.plot:
            # append latest data
            for sample in new_data_int:
                pre_record_buf_int.append(sample)
            # set y data
            line.set_ydata(np.array(pre_record_buf_int))
            # set line color
            if is_recording:
                line.set_color('r')
            else:
                line.set_color('g')
            # update graph
            fig.canvas.draw()
            fig.canvas.flush_events()

if __name__ == "__main__":
    logger = create_logger("recorder")
    args = parse_arguments()
    if args.verbose:
        logger.setLevel(logging.DEBUG)
        logger.info("set verbose logging mode")

    if args.plot:
        import matplotlib
        matplotlib.use('TKAgg')
        import matplotlib.pyplot as plt

    main(args)

    exit(0)


import os
import sys
import pickle
import mxnet as mx
import argparse
import numpy as np
import sklearn
import sklearn.preprocessing

parser = argparse.ArgumentParser(description='face model test')
# general
parser.add_argument('--model', default='./model/iqiyia1,40', help='')
parser.add_argument('--gpu', default=0, type=int, help='gpu id')
parser.add_argument('--inputs', default='/media/3T_disk/my_datasets/iqiyi_vid/feat_testa', help='')
parser.add_argument('--output', default='/media/3T_disk/my_datasets/iqiyi_vid/pred_testa', help='')
args = parser.parse_args()

print(args)
MODE = 2
emb_size = 0
model = None

def get_score(feat):
  data = mx.nd.array(feat)
  db = mx.io.DataBatch(data=(data,))
  model.forward(db, is_train=False)
  xscore = model.get_outputs()[0].asnumpy()
  #print(xscore.shape)
  return xscore

inputs = args.inputs.split(',')

streams = []
for input in inputs:
  filename = input
  assert os.path.exists(filename)
  f = open(filename, 'rb')
  streams.append(f)

DB_NAME = {}

for f in streams:
  while True:
    try:
      item = pickle.load(f)
    except:
      break
    name = item[0]
    if name not in DB_NAME:
      DB_NAME[name] = []
    DB_NAME[name].append(item)

for f in streams:
  f.close()

print('total', len(DB_NAME))
fout = open(args.output, 'wb')
#ret_map = {}
batch_size = 32
pp = 0
TOPK = 100
N = 200
S = 10000.0

def process(datas):
  name_list = []
  feat_list = []
  for data in datas:
    name_list.append(data[0])
    feat_list.append(data[1])
  feats = np.array(feat_list)
  xscores = get_score(feats)
  assert len(name_list)==xscores.shape[0]
  #print(feats.shape, xscores.shape)
  for i in range(len(name_list)):
    name = name_list[i]
    xscore = xscores[i]
    pickle.dump((name, xscore), fout, protocol=pickle.HIGHEST_PROTOCOL)

#S = 1.0
buf = []
for name, items in DB_NAME.iteritems():
  pp+=1
  if pp%1000==0:
    print('processing', pp)
  #if len(items)!=len(streams):
  #  continue
  arrs = []
  for item in items:
    arrs.append(item[1])
  feat = np.concatenate(arrs, axis=1).flatten()
  if model is None:
    emb_size = len(feat)
    print('emb_size', emb_size)
    _vec = args.model.split(',')
    assert len(_vec)==2
    prefix = _vec[0]
    epoch = int(_vec[1])
    print('loading',prefix, epoch)
    ctx = mx.gpu(args.gpu)
    sym, arg_params, aux_params = mx.model.load_checkpoint(prefix, epoch)
    all_layers = sym.get_internals()
    sym = all_layers['fc7_output']
    sym = mx.sym.SoftmaxActivation(sym)
    model = mx.mod.Module(symbol=sym, context=ctx, label_names = None)
    model.bind(data_shapes=[('data', (1, emb_size))])
    model.set_params(arg_params, aux_params)
  #feat = sklearn.preprocessing.normalize(feat)
  #label = items[0][2]
  flag = items[0][3]
  # assert flag==3
  buf.append( (name, feat) )
  if len(buf)==batch_size:
    process(buf)
    buf = []

if len(buf)>0:
  process(buf)

fout.close()
sys.exit(0)


import os
os.environ["CUDA_VISIBLE_DEVICES"]="0"

import numpy as np
import re

import tensorflow as tf
import tensorflow.keras.backend as K
import tensorflow.keras.layers as KL
import tensorflow.keras.models as KM
import tensorflow.keras.utils as KU
from tensorflow.keras.layers import Layer

import tensorflow_addons as tfa

gpus = tf.config.experimental.list_physical_devices('GPU')
for gpu in gpus:
        tf.config.experimental.set_memory_growth(gpu, True)

# class BatchNorm(KL.BatchNormalization):
class BatchNorm(tfa.layers.GroupNormalization):
    """Extends the Keras BatchNormalization class to allow a central place
    to make changes if needed.

    Batch normalization has a negative effect on training if batches are small
    so this layer is often frozen (via setting in Config class) and functions
    as linear layer.
    """
    def call(self, inputs, training=None):
        """
        Note about training values:
            None: Train BN layers. This is the normal mode
            False: Freeze BN layers. Good when batch size is small
            True: (don't use). Set layer in training mode even when making inferences
        """
        # return super(self.__class__, self).call(inputs, training=training)
        return super(self.__class__, self).call(inputs)

############################################################
#  Resnet Graph
############################################################

# Code adopted from:
# https://github.com/fchollet/deep-learning-models/blob/master/resnet50.py

def identity_block(input_tensor, kernel_size, filters, stage, block,
                   use_bias=True, train_bn=True):
    """The identity_block is the block that has no conv layer at shortcut
    # Arguments
        input_tensor: input tensor
        kernel_size: default 3, the kernel size of middle conv layer at main path
        filters: list of integers, the nb_filters of 3 conv layer at main path
        stage: integer, current stage label, used for generating layer names
        block: 'a','b'..., current block label, used for generating layer names
        use_bias: Boolean. To use or not use a bias in conv layers.
        train_bn: Boolean. Train or freeze Batch Norm layers
    """
    nb_filter1, nb_filter2, nb_filter3 = filters
    conv_name_base = 'res' + str(stage) + block + '_branch'
    bn_name_base = 'bn' + str(stage) + block + '_branch'

    x = KL.Conv2D(nb_filter1, (1, 1), name=conv_name_base + '2a',
                  use_bias=use_bias)(input_tensor)
    x = BatchNorm(name=bn_name_base + '2a')(x, training=train_bn)
    x = KL.Activation('relu')(x)

    x = KL.Conv2D(nb_filter2, (kernel_size, kernel_size), padding='same',
                  name=conv_name_base + '2b', use_bias=use_bias)(x)
    x = BatchNorm(name=bn_name_base + '2b')(x, training=train_bn)
    x = KL.Activation('relu')(x)

    x = KL.Conv2D(nb_filter3, (1, 1), name=conv_name_base + '2c',
                  use_bias=use_bias)(x)
    x = BatchNorm(gamma_initializer='zeros', name=bn_name_base + '2c')(x, training=train_bn)

    x = KL.Add()([x, input_tensor])
    x = KL.Activation('relu', name='res' + str(stage) + block + '_out')(x)
    return x

def conv_block(input_tensor, kernel_size, filters, stage, block,
               strides=(2, 2), use_bias=True, train_bn=True):
    """conv_block is the block that has a conv layer at shortcut
    # Arguments
        input_tensor: input tensor
        kernel_size: default 3, the kernel size of middle conv layer at main path
        filters: list of integers, the nb_filters of 3 conv layer at main path
        stage: integer, current stage label, used for generating layer names
        block: 'a','b'..., current block label, used for generating layer names
        use_bias: Boolean. To use or not use a bias in conv layers.
        train_bn: Boolean. Train or freeze Batch Norm layers
    Note that from stage 3, the first conv layer at main path is with subsample=(2,2)
    And the shortcut should have subsample=(2,2) as well
    """
    nb_filter1, nb_filter2, nb_filter3 = filters
    conv_name_base = 'res' + str(stage) + block + '_branch'
    bn_name_base = 'bn' + str(stage) + block + '_branch'

    x = KL.Conv2D(nb_filter1, (1, 1), strides=strides,
                  name=conv_name_base + '2a', use_bias=use_bias)(input_tensor)
    x = BatchNorm(name=bn_name_base + '2a')(x, training=train_bn)
    x = KL.Activation('relu')(x)

    x = KL.Conv2D(nb_filter2, (kernel_size, kernel_size), padding='same',
                  name=conv_name_base + '2b', use_bias=use_bias)(x)
    x = BatchNorm(name=bn_name_base + '2b')(x, training=train_bn)
    x = KL.Activation('relu')(x)

    x = KL.Conv2D(nb_filter3, (1, 1), name=conv_name_base +
                  '2c', use_bias=use_bias)(x)
    x = BatchNorm(name=bn_name_base + '2c')(x, training=train_bn)

    shortcut = KL.Conv2D(nb_filter3, (1, 1), strides=strides,
                         name=conv_name_base + '1', use_bias=use_bias)(input_tensor)
    shortcut = BatchNorm(gamma_initializer='zeros', name=bn_name_base + '1')(shortcut, training=train_bn)

    x = KL.Add()([x, shortcut])
    x = KL.Activation('relu', name='res' + str(stage) + block + '_out')(x)
    return x

def resnet_graph(input_image, architecture, stage5=False, train_bn=True):
    """Build a ResNet graph.
        architecture: Can be resnet50 or resnet101
        stage5: Boolean. If False, stage5 of the network is not created
        train_bn: Boolean. Train or freeze Batch Norm layers
    """
    assert architecture in ["resnet50", "resnet101"]
    # Stage 1
    x = KL.ZeroPadding2D((3, 3))(input_image)
    x = KL.Conv2D(64, (7, 7), strides=(2, 2), name='conv1', use_bias=True)(x)
    x = BatchNorm(name='bn_conv1')(x, training=train_bn)
    x = KL.Activation('relu')(x)
    C1 = x = KL.MaxPooling2D((3, 3), strides=(2, 2), padding="same")(x)
    # Stage 2
    x = conv_block(x, 3, [64, 64, 256], stage=2, block='a', strides=(1, 1), train_bn=train_bn)
    x = identity_block(x, 3, [64, 64, 256], stage=2, block='b', train_bn=train_bn)
    C2 = x = identity_block(x, 3, [64, 64, 256], stage=2, block='c', train_bn=train_bn)
    # Stage 3
    x = conv_block(x, 3, [128, 128, 512], stage=3, block='a', train_bn=train_bn)
    x = identity_block(x, 3, [128, 128, 512], stage=3, block='b', train_bn=train_bn)
    x = identity_block(x, 3, [128, 128, 512], stage=3, block='c', train_bn=train_bn)
    C3 = x = identity_block(x, 3, [128, 128, 512], stage=3, block='d', train_bn=train_bn)
    # Stage 4
    x = conv_block(x, 3, [256, 256, 1024], stage=4, block='a', train_bn=train_bn)
    block_count = {"resnet50": 5, "resnet101": 22}[architecture]
    for i in range(block_count):
        x = identity_block(x, 3, [256, 256, 1024], stage=4, block=chr(98 + i), train_bn=train_bn)
    C4 = x
    # Stage 5
    if stage5:
        x = conv_block(x, 3, [512, 512, 2048], stage=5, block='a', train_bn=train_bn)
        x = identity_block(x, 3, [512, 512, 2048], stage=5, block='b', train_bn=train_bn)
        C5 = x = identity_block(x, 3, [512, 512, 2048], stage=5, block='c', train_bn=train_bn)
    else:
        C5 = None
    return [C1, C2, C3, C4, C5]

def load_image_gt(dataset, image_id, augmentation=None):
    image = dataset.load_image(image_id)
    images = np.array([image, image])
    if augmentation:
        images = np.array(augmentation(images=images))
    return images

class DataGenerator(KU.Sequence):
    def __init__(self, dataset, config, shuffle=True, augmentation=None):
        self.image_ids = np.copy(dataset.image_ids)
        self.dataset = dataset
        self.config = config

        self.shuffle = shuffle
        self.augmentation = augmentation
        self.batch_size = self.config.BATCH_SIZE

        if self.shuffle is True:
            np.random.shuffle(self.image_ids)

    def __len__(self):
        return int(np.ceil(len(self.image_ids) / float(self.batch_size))) - 1

    def __getitem__(self, idx):
        return self.data_generator(
            self.image_ids[idx*self.batch_size:(idx+1)*self.batch_size])

    def data_generator(self, image_ids):
        b = 0
        while b < self.batch_size and b < image_ids.shape[0]:
            image_id = image_ids[b]
            paired_images = load_image_gt(
                self.dataset, image_id, self.augmentation)

            if b == 0:
                batch_images = np.zeros(
                    (2*self.batch_size,) + paired_images.shape[1:],
                    dtype=np.float32)
                batch_labels = np.zeros(
                    (2*self.batch_size)
                )

            batch_images[2*b:2*b+2] = mold_image(paired_images, self.config)
            batch_labels[2*b:2*b+2] = np.array([2*b+1, 2*b])
            b += 1

            if b >= self.batch_size:
                inputs = [batch_images]
                outputs = [batch_labels]
                return inputs, outputs

    def on_epoch_end(self):
        if self.shuffle is True:
            np.random.shuffle(self.image_ids)

class OnEpochEnd(tf.keras.callbacks.Callback):
    """Workaround to deal with bug in Tensorflow 2.1.0

    "tf.keras.fit not calling Sequence.on_epoch_end" refer
    to tenstflow/issues/#35911
    """
    def __init__(self, callbacks):
        self.callbacks = callbacks

    def on_epoch_end(self, epoch, logs=None):
        for callback in self.callbacks:
            callback()

# TODO: Momentum weight
class MoCoQueue(Layer):
    """This layer provides queue mechanism to save intput as previous projection results,
    and return current the whole queue as negative sample in each iteration.
    """
    def __init__(self, config):
        super(MoCoQueue, self).__init__()
        self.batch_size = config.BATCH_SIZE
        self.max_queue_length = config.MAX_QUEUE_LENGTH
        self.c = (self.max_queue_length+2*self.batch_size) // (2*self.batch_size)

    def build(self, input_shape):
        self.embedding_dim = input_shape[-1]
        init = tf.random_normal_initializer()
        self.keys = tf.Variable(
            initial_value=init(shape=(self.max_queue_length, self.embedding_dim), dtype='float32'),
            trainable=False)

    def call(self, new_keys):
        keys = self.keys
        cat = tf.concat([new_keys, self.keys], 0)
        self.keys.assign(
            tf.slice(cat, [0, 0], [self.max_queue_length, self.embedding_dim],))
        return keys

class CosineSimilarity(Layer):
    """Compute in-batch similarity and similarities between current batch and MoCo queue.
    """
    def __init__(self, config):
        super(CosineSimilarity, self).__init__()
        large_num = 1e9
        self.temperature = config.TEMPERATURE

        self.batch_size = config.BATCH_SIZE
        self.max_queue_length = config.MAX_QUEUE_LENGTH
        self.c = (self.max_queue_length) // (2*self.batch_size)

        self.mask = large_num*tf.eye(2*self.batch_size)

    def call(self, z, moco):
        z_moco = K.dot(z, K.transpose(moco))  / self.temperature
        z = K.dot(z, K.transpose(z))  / self.temperature
        z = z - self.mask
        z = tf.concat([z, z_moco], axis=-1)
        return z

class SimCLRv2(object):
    def __init__(self, config):
        self.config = config
        self.build(mode=self.config.MODE)

    def build(self, mode='training'):
        config = self.config

        # Inputs
        input_image = KL.Input(
            shape=[None, None, 3], name="input_image")

        # Build Resnet
        _, C2, C3, C4, C5 = resnet_graph(input_image, config.BACKBONE,
                                         stage5=True, train_bn=config.TRAIN_BN)

        z = KL.GlobalAveragePooling2D()(C5)

        z = BatchNorm(name='projection_bn')(z)

        z = KL.Dense(config.NUM_HIDDENS[0], name='projection1')(z)
        z = KL.Activation('relu')(z)
        z = KL.Dense(config.NUM_HIDDENS[1], name='projection2')(z)
        z = KL.Activation('relu')(z)
        z = KL.Dense(config.NUM_HIDDENS[2], name='projection3')(z)

        z = KL.Lambda(lambda x: tf.math.l2_normalize(x, axis=1))(z)

        if mode == 'training':
            keys = MoCoQueue(config)(  z)
            logits = CosineSimilarity(config)(z, keys)
            probs = KL.Activation('softmax')(logits)
            output = probs
        else:
            output = z
        self.model = KM.Model(input_image, output)

    def load_h5(self, path):
        self.model.load_weights(path, by_name=True)

    def save_h5(self, path):
        self.model.save_weights(path)

    def compile(self, learning_rate, lookahead=True):
        config = self.config
        # Optimizer object
        if config.OPTIMIZER == "SGD+Momentum":
            optimizer = tf.keras.optimizers.SGD(
                lr=learning_rate, momentum=momentum)
        elif config.OPTIMIZER == "AdamW":
            optimizer = tfa.optimizers.AdamW(learning_rate=learning_rate, weight_decay=1e-8)
        elif config.OPTIMIZER == "Ranger":
            optimizer = tfa.optimizers.RectifiedAdam(lr=learning_rate)
        else:
            raise ValueError("Your config.OPTIMIZER is not given or not supported in this repo.")

        if config.LOOKAHEAD:
            optimizer = tfa.optimizers.Lookahead(optimizer)

        # Add L2 Regularization
        # Skip gamma and beta weights of batch normalization layers.
        reg_losses = [
            keras.regularizers.l2(config.WEIGHT_DECAY)(w) / tf.cast(tf.size(w), tf.float32)
            for w in self.model.trainable_weights
            if 'gamma' not in w.name and 'beta' not in w.name]
        self.model.add_loss(tf.add_n(reg_losses))

        self.model.compile(
            optimizer=optimizer,
            loss='sparse_categorical_crossentropy')

    def set_trainable(self, layer_regex, keras_model=None, indent=0, verbose=1):
        """Sets model layers as trainable if their names match
        the given regular expression.
        """
        # Print message on the first call (but not on recursive calls)
        if verbose > 0 and keras_model is None:
            print("Selecting layers to train")

        keras_model = keras_model or self.keras_model

        # In multi-GPU training, we wrap the model. Get layers
        # of the inner model because they have the weights.
        layers = keras_model.inner_model.layers if hasattr(keras_model, "inner_model")\
            else keras_model.layers

        for layer in layers:
            # Is the layer a model?
            if layer.__class__.__name__ == 'Model':
                print("In model: ", layer.name)
                self.set_trainable(
                    layer_regex, keras_model=layer, indent=indent + 4)
                continue

            if not layer.weights:
                continue
            # Is it trainable?
            trainable = bool(re.fullmatch(layer_regex, layer.name))
            # Update layer. If layer is a container, update inner layer.
            if layer.__class__.__name__ == 'TimeDistributed':
                layer.layer.trainable = trainable
            else:
                layer.trainable = trainable
            # Print trainable layer names
            if trainable and verbose > 0:
                print("{}{:20}   ({})".format(" " * indent, layer.name,
                                            layer.__class__.__name__))

    def train(self, dataset, augmentation, epochs=1, learning_rate=1e-2, layers='all'):

        # Pre-defined layer regular expressions
        layer_regex = {
            # From a specific Resnet stage and up
            "3+": r"(res3.*)|(bn3.*)|(res4.*)|(bn4.*)|(res5.*)|(bn5.*)",
            "4+": r"(res4.*)|(bn4.*)|(res5.*)|(bn5.*)",
            "5+": r"(res5.*)|(bn5.*))",
            "resnet": r"(res.*)|(bn.*)",
            "projection": r"(projection_.*)",
            # All layers
            "all": ".*",
        }
        if layers in layer_regex.keys():
            layers = layer_regex[layers]

        train_generator = DataGenerator(
            dataset, self.config, augmentation=augmentation
            )
        callbacks = [
            OnEpochEnd([train_generator.on_epoch_end]),
            ]
        self.set_trainable(layers, keras_model=self.model, verbose=0)
        self.compile(learning_rate=learning_rate)
        self.model.fit(
            train_generator,
            epochs=epochs,
            use_multiprocessing=True,
            callbacks=callbacks,
            )

def mold_image(images, config):
    """Expects an RGB image (or array of images) and subtracts
    the mean pixel and converts it to float. Expects image
    colors in RGB order.
    """
    return images.astype(np.float32) - config.MEAN_PIXEL


# -*- coding: utf-8 -*-
"""
This is a German NER implementation for the dataset GermEval 2014. Also check the folder 'Session 1 - SENNA' for some further information.

This model uses a bi-directional LSTM and runs over an input sentence. The output of the BiLSTM is inputted to a softmax-layer to derive
the probabilities for the different tags.

Single BiLSTM (100 hidden units), after 15 epochs:
Dev-Data: Prec: 0.789, Rec: 0.739, F1: 0.763
Test-Data: Prec: 0.781, Rec: 0.717, F1: 0.747

Stacked BiLSTM (2 layers, 64 hidden states), after 25 epochs:
Dev-Data: Prec: 0.804, Rec: 0.763, F1: 0.783
Test-Data: Prec: 0.795, Rec: 0.738, F1: 0.766

Code was written & tested with:
- Python 2.7 & Python 3.6
- Theano 0.9.0 and tensorflow 1.2.1
- Keras 2.0.5

@author: Nils Reimers, www.deeplearning4nlp.com
"""
from __future__ import print_function
import numpy as np
import random
import time
import gzip

import sys
if (sys.version_info > (3, 0)):
    import pickle as pkl
else:
    #Python 2.7 imports
    import cPickle as pkl

import BIOF1Validation

import keras
import keras
from keras.models import Model
from keras.layers import *

f = gzip.open('pkl/embeddings.pkl.gz', 'rb')
embeddings = pkl.load(f)
f.close()

label2Idx = embeddings['label2Idx']
wordEmbeddings = embeddings['wordEmbeddings']
caseEmbeddings = embeddings['caseEmbeddings']

#Inverse label mapping
idx2Label = {v: k for k, v in label2Idx.items()}

f = gzip.open('pkl/data.pkl.gz', 'rb')
train_data = pkl.load(f)
dev_data = pkl.load(f)
test_data = pkl.load(f)
f.close()

#####################################
#
# Create the  Network
#
#####################################

n_out = len(label2Idx)

words_input = Input(shape=(None,), dtype='int32', name='words_input')
words = Embedding(input_dim=wordEmbeddings.shape[0], output_dim=wordEmbeddings.shape[1],  weights=[wordEmbeddings], trainable=False)(words_input)

casing_input = Input(shape=(None,), dtype='int32', name='casing_input')
casing = Embedding(output_dim=caseEmbeddings.shape[1], input_dim=caseEmbeddings.shape[0], weights=[caseEmbeddings], trainable=False)(casing_input)

output = concatenate([words, casing])
output = Bidirectional(LSTM(50, return_sequences=True, dropout=0.25, recurrent_dropout=0.25))(output)
output = TimeDistributed(Dense(n_out, activation='softmax'))(output)

#Create our model and compile it using Nadam optimizer with categorical cross-entropy for sparse y-labels
model = Model(inputs=[words_input, casing_input], outputs=[output])
model.compile(loss='sparse_categorical_crossentropy', optimizer='nadam')
model.summary()

##################################
#
# Training of the Network
#
##################################

def iterate_minibatches(dataset):
    endIdx = len(dataset)

    for idx in range(endIdx):
        tokens, casing, labels = dataset[idx]

        labels = np.expand_dims([labels], -1)
        yield labels, np.asarray([tokens]), np.asarray([casing])

def tag_dataset(dataset):
    correctLabels = []
    predLabels = []
    for tokens, casing, labels in dataset:
        tokens = np.asarray([tokens])
        casing = np.asarray([casing])
        pred = model.predict([tokens, casing], verbose=False)[0]
        pred = pred.argmax(axis=-1) #Predict the classes
        correctLabels.append(labels)
        predLabels.append(pred)

    return predLabels, correctLabels

number_of_epochs = 20

print("%d epochs" % number_of_epochs)

print("%d train sentences" % len(train_data))
print("%d dev sentences" % len(dev_data))
print("%d test sentences" % len(test_data))

for epoch in range(number_of_epochs):
    print("--------- Epoch %d -----------" % epoch)
    random.shuffle(train_data)
    start_time = time.time()

    #Train one sentence at a time (i.e. online training) to avoid padding of sentences
    cnt = 0
    for batch in iterate_minibatches(train_data):
        labels, tokens, casing = batch
        model.train_on_batch([tokens, casing], labels)
        cnt += 1

        if cnt % 100 == 0:
            print('Sentence: %d / %d' % (cnt, len(train_data)), end='\r')
    print("%.2f sec for training                 " % (time.time() - start_time))

    #Performance on dev dataset
    predLabels, correctLabels = tag_dataset(dev_data)
    pre_dev, rec_dev, f1_dev = BIOF1Validation.compute_f1(predLabels, correctLabels, idx2Label)
    print("Dev-Data: Prec: %.3f, Rec: %.3f, F1: %.3f" % (pre_dev, rec_dev, f1_dev))

    #Performance on test dataset
    predLabels, correctLabels = tag_dataset(test_data)
    pre_test, rec_test, f1_test= BIOF1Validation.compute_f1(predLabels, correctLabels, idx2Label)
    print("Test-Data: Prec: %.3f, Rec: %.3f, F1: %.3f" % (pre_test, rec_test, f1_test))

    print("%.2f sec for evaluation" % (time.time() - start_time))
    print("")

2017-07_Seminar/Session 4 - LSTM Sequence Classification/code/NER_BiLSTM.py


import numpy as np
import cv2
import argparse

import threading

import Object
#import StopLine

from model import NeuralNetwork

class CollectTrainingData(object):

    def __init__(self, client, steer):
        import argparse

        self.client = client
        self.steer = steer

        #self.args = Namespace(classes='yolov3.txt', config='yolov2-tiny.cfg', image='dog.jpg', weights='yolov2-tiny.weights')
        #self.stopline = StopLine.Stop()

        #self.dect = Object.Object_Detection(self.steer) # hcw

        # model create

        #self.model = NeuralNetwork()
        #self.model.load_model(path = 'model_data/video_model_1.h5')

    def collect(self):

        #################### detection code inserted ################################################

        # function to get the output layer names
        # in the architecture
        def get_output_layers(net):

            layer_names = net.getLayerNames()

            output_layers = [layer_names[i[0] - 1] for i in net.getUnconnectedOutLayers()]

            return output_layers

        # function to draw bounding box on the detected object with class name

        def draw_prediction(img, class_id, confidence, x, y, x_plus_w, y_plus_h):

            label = str(classes[class_id])

            color = COLORS[class_id]

            cv2.rectangle(img, (x, y), (x_plus_w, y_plus_h), color, 2)

            cv2.putText(img, label, (x - 10, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2)

        ###############################################################################################

        print("Start video stream")

        stream_bytes = b' '
        test = 0
        cnt = 0
        while True :
	        #print("WHY")
            stream_bytes += self.client.recv(1024)
            first = stream_bytes.find(b'\xff\xd8')
            last = stream_bytes.find(b'\xff\xd9')

#########################################

##########################################

            if first != -1 and last != -1:
                test = test+1
                print("IN TRY", test)
                jpg = stream_bytes[first:last + 2]
                stream_bytes = stream_bytes[last + 2:]
                gray = cv2.imdecode(np.frombuffer(jpg, dtype=np.uint8), cv2.IMREAD_GRAYSCALE)
                image = cv2.imdecode(np.frombuffer(jpg, dtype=np.uint8), cv2.IMREAD_COLOR)

                print(image)
                print('type : ',type(image))
                print('shape : ', image.shape)

################# detection code inserted ##################

                Width = image.shape[1]
                Height = image.shape[0]
                scale = 0.00392

                # read class names from text file
                classes = None

                with open('yolov3.txt', 'r') as f:
                    classes = [line.strip() for line in f.readlines()]

                # generate different colors for different classes
                COLORS = np.random.uniform(0, 255, size=(len(classes), 3))

                # read pre-trained model and config file
                net = cv2.dnn.readNet('yolov2-tiny.weights', 'yolov2-tiny.cfg')

                # create input blob
                blob = cv2.dnn.blobFromImage(image, scale, (416, 416), (0, 0, 0), True, crop=False)

                # set input blob for the network
                net.setInput(blob)

                if cnt % 10 == 0:

                    # run inference through the network
                    # and gather predictions from output layers
                    outs = net.forward(get_output_layers(net))

                    # initialization
                    class_ids = []
                    confidences = []
                    boxes = []
                    conf_threshold = 0.5
                    nms_threshold = 0.4

                    # for each detetion from each output layer
                    # get the confidence, class id, bounding box params
                    # and ignore weak detections (confidence < 0.5)

                    for out in outs:
                        for detection in out:
                            scores = detection[5:]
                            class_id = np.argmax(scores)
                            confidence = scores[class_id]
                            if confidence > 0.5:
                                center_x = int(detection[0] * Width)
                                center_y = int(detection[1] * Height)
                                w = int(detection[2] * Width)
                                h = int(detection[3] * Height)
                                x = center_x - w / 2
                                y = center_y - h / 2
                                class_ids.append(class_id)
                                confidences.append(float(confidence))
                                boxes.append([x, y, w, h])

                    # apply non-max suppression

                    indices = cv2.dnn.NMSBoxes(boxes, confidences, conf_threshold, nms_threshold)

                    # go through the detections remaining
                    # after nms and draw boundng box

                    for i in indices:
                        i = i[0]
                        box = boxes[i]
                        x = box[0]
                        y = box[1]
                        w = box[2]
                        h = box[3]
                        draw_prediction(image, class_ids[i], confidences[i], round(x), round(y), round(x + w),
                                        round(y + h))

                ############################################################

                cv2.imshow('image',image)

#################################
#		inserted code start (by hcw)
#################################

##################################
#		inserted code end
##################################

                    #print("RGB: ",rgb)

                    #cv2.imshow('Origin', rgb)
                    #cv2.waitKey(1)
                    #cv2.imshow('GRAY', image)
                    #cv2.imshow('roi', roi)
                    #print("hihi3")
                    # reshape the roi image into a vector
                   #image_array = np.reshape(roi, (-1, 120, 320, 1))
                    #print("hihi2")

                    # neural network makes prediction
                    #self.steer.Set_Line(self.model.predict(image_array))
                    #self.steer.Set_Stopline(self.stopline.GetStopLine(roi2))
                    #print(self.dect.Detection(rgb))
                    #print("hihi")

                    #self.dect.Detection(rgb)
                    #print("hi")

                    #self.steer.Control()
                #cv2.imshow('rgb',rgb)
                if cv2.waitKey(1) & 0xFF == ord('q'):
                    break

        cv2.destroyAllWindows()	 # inserted (by hcw)


# -*- coding: utf-8 -*-
from ..._core import bolton_q_sat, ensure_contiguous_state
from sympl import (
    ImplicitTendencyComponent, get_constant, initialize_numpy_arrays_with_properties)
import numpy as np
import logging
try:
    from . import _emanuel_convection
except ImportError as error:
    logging.warning(
        'Import failed. Emanuel Convection is likely not compiled and will not '
        'be available.'
    )
    print(error)

class EmanuelConvection(ImplicitTendencyComponent):
    """
    The Emanuel convection scheme from `[Emanuel and Zivkovic-Rothman]`_

    .. _[Emanuel and Zivkovic-Rothman]:
            http://journals.ametsoc.org/doi/abs/10.1175/1520-0469(1999)056%3C1766%3ADAEOAC%3E2.0.CO%3B2

    """

    input_properties = {
        'air_temperature': {
            'dims': ['*', 'mid_levels'],
            'units': 'degK',
        },
        'specific_humidity': {
            'dims': ['*', 'mid_levels'],
            'units': 'kg/kg',
        },
        'eastward_wind': {
            'dims': ['*', 'mid_levels'],
            'units': 'm s^-1',
        },
        'northward_wind': {
            'dims': ['*', 'mid_levels'],
            'units': 'm s^-1',
        },
        'air_pressure': {
            'dims': ['*', 'mid_levels'],
            'units': 'mbar',
        },
        'air_pressure_on_interface_levels': {
            'dims': ['*', 'interface_levels'],
            'units': 'mbar',
        },
        'cloud_base_mass_flux': {
            'dims': ['*'],
            'units': 'kg m^-2 s^-1',
        },
    }

    diagnostic_properties = {
        'convective_state': {
            'dims': ['*'],
            'units': 'dimensionless',
            'dtype': np.int32,
        },
        'convective_precipitation_rate': {
            'dims': ['*'],
            'units': 'mm day^-1',
        },
        'convective_downdraft_velocity_scale': {
            'dims': ['*'],
            'units': 'm s^-1',
        },
        'convective_downdraft_temperature_scale': {
            'dims': ['*'],
            'units': 'degK',
        },
        'convective_downdraft_specific_humidity_scale': {
            'dims': ['*'],
            'units': 'kg/kg',
        },
        'cloud_base_mass_flux': {
            'dims': ['*'],
            'units': 'kg m^-2 s^-1',
        },
        'atmosphere_convective_available_potential_energy': {
            'dims': ['*'],
            'units': 'J kg^-1',
        },
        'air_temperature_tendency_from_convection': {
            'dims': ['*', 'mid_levels'],
            'units': 'degK day^-1',
        }
    }

    tendency_properties = {
        'air_temperature': {'units': 'degK s^-1'},
        'specific_humidity': {'units': 'kg/kg s^-1'},
        'eastward_wind': {'units': 'm s^-2'},
        'northward_wind': {'units': 'm s^-2'},
    }

    def __init__(self,
                 minimum_convecting_layer=1,
                 autoconversion_water_content_threshold=0.0011,
                 autoconversion_temperature_threshold=-55,
                 entrainment_mixing_coefficient=1.5,
                 downdraft_area_fraction=0.05,
                 precipitation_fraction_outside_cloud=0.12,
                 speed_water_droplets=50.0,
                 speed_snow=5.5,
                 rain_evaporation_coefficient=1.0,
                 snow_evaporation_coefficient=0.8,
                 convective_momentum_transfer_coefficient=0.7,
                 downdraft_surface_velocity_coefficient=10.0,
                 convection_bouyancy_threshold=0.9,
                 mass_flux_relaxation_rate=0.1,
                 mass_flux_damping_rate=0.1,
                 reference_mass_flux_timescale=300.,
                 **kwargs):
        """

        Args:

            minimum_convecting_layer (int, optional):
                The least model level from which convection can be initiated. Normally set
                to :code:`1` if using bulk PBL schemes. Else, it should be set to the first
                model level at which the temperature is defined.

            autoconversion_water_content_threshold (float, optional):
                The amount of water vapour in :math:`kg/kg`
                above which condensation occurs in warm (above freezing point of water)
                clouds. This value linearly reduces to zero between the freezing point and
                the :code:`autoconversion_temperature_threshold`.

            autoconversion_temperature_threshold (float, optional):
                The temperature in :math:`^\circ C` below which
                all water vapour is converted to rain/snow.

            entrainment_mixing_coefficient (float, optional):
                The coefficient of mixing for entrainment of environmental air into
                the cloud.

            downdraft_area_fraction (float, optional):
                The fractional area covered by unsaturated downdrafts.

            precipitation_fraction_outside_cloud (float, optional):
                The fraction of precipitation falling outside the cloud.

            speed_water_droplets (float, optional):
                The speed of descent of water droplets in :math:`Pa/s`.

            speed_snow (float, optional):
                The speed of descent of snow in :math:`Pa/s`.

            rain_evaporation_coefficient (float, optional):
                Coefficient governing the rate of evaporation of rain.

            snow_evaporation_coefficient (float, optional):
                Coefficient governing the rate of evaporation of snow.

            convective_momentum_transfer_coefficient (float, optional):
                Coefficient **between 0 and 1** governing momentum transport
                by clouds. A value of 1 **shuts off** momentum transport.

            downdraft_surface_velocity_coefficient (float, optional):
                Coefficient mulitplying the downdraft mass flux to calculate
                the downdraft velocity scale.

            convection_bouyancy_threshold (float, optional):
                The maximum negative temperature perturbation in :math:`degK` a parcel can
                have below the temperature at its level of free convection.
                If difference is greater, and previous cloud base mass flux
                is zero, there is no convection.

            mass_flux_relaxation_rate (float, optional):
                Coefficient governing the rate of relaxation to subcloud-layer
                quasi-equilibrium.

            mass_flux_damping_rate (float, optional):
                Coefficient which damps the currently calculated mass flux towards
                the value from the previous time step.

            reference_mass_flux_timescale (float, optional):
                Timescale used to calculate the actual damping coefficient along with
                :code:`mass_flux_damping_rate` and the current time step.

        """

        if (convective_momentum_transfer_coefficient < 0 or
                convective_momentum_transfer_coefficient > 1):
            raise ValueError("Momentum transfer coefficient must be between 0 and 1.")

        if (downdraft_area_fraction < 0 or
                downdraft_area_fraction > 1):
            raise ValueError("Downdraft fraction must be between 0 and 1.")

        if (precipitation_fraction_outside_cloud < 0 or
                precipitation_fraction_outside_cloud > 1):
            raise ValueError("Outside cloud precipitation fraction must be between 0 and 1.")

        self._con_mom_txfr = convective_momentum_transfer_coefficient
        self._downdraft_area_frac = downdraft_area_fraction
        self._precip_frac_outside_cloud = precipitation_fraction_outside_cloud
        self._min_conv_layer = minimum_convecting_layer
        self._crit_humidity = autoconversion_water_content_threshold
        self._crit_temp = autoconversion_temperature_threshold
        self._entrain_coeff = entrainment_mixing_coefficient
        self._droplet_speed = speed_water_droplets
        self._snow_speed = speed_snow
        self._rain_evap = rain_evaporation_coefficient
        self._snow_evap = snow_evaporation_coefficient
        self._beta = downdraft_surface_velocity_coefficient
        self._dtmax = convection_bouyancy_threshold
        self._mf_damp = mass_flux_damping_rate
        self._alpha = mass_flux_relaxation_rate
        self._mf_timescale = reference_mass_flux_timescale
        self._ntracers = 0
        self._set_fortran_constants()
        super(EmanuelConvection, self).__init__(**kwargs)

    def _set_fortran_constants(self):
        self._g = get_constant('gravitational_acceleration', 'm/s^2')
        self._Cpd = get_constant('heat_capacity_of_dry_air_at_constant_pressure', 'J/kg/degK')
        self._Cpv = get_constant('heat_capacity_of_vapor_phase', 'J/kg/degK')
        self._Rdair = get_constant('gas_constant_of_dry_air', 'J/kg/degK')
        self._Rcond = get_constant('gas_constant_of_vapor_phase', 'J/kg/degK')
        self._Lv = get_constant('latent_heat_of_condensation', 'J/kg')
        self._rho_condensible = get_constant('density_of_liquid_phase', 'kg/m^3')
        self._Cl = get_constant('specific_enthalpy_of_vapor_phase', 'J/kg')
        _emanuel_convection.init_emanuel_convection(
            self._min_conv_layer,
            self._crit_humidity,
            self._crit_temp, self._entrain_coeff,
            self._downdraft_area_frac,
            self._precip_frac_outside_cloud,
            self._droplet_speed, self._snow_speed,
            self._rain_evap, self._snow_evap,
            self._con_mom_txfr, self._dtmax,
            self._beta, self._alpha, self._mf_damp,
            self._Cpd, self._Cpv, self._Cl,
            self._Rcond, self._Rdair,
            self._Lv, self._g,
            self._rho_condensible, self._mf_timescale)

    @ensure_contiguous_state
    def array_call(self, raw_state, timestep):
        """
        Get convective heating and moistening.

        Args:

            raw_state (dict):
                The state dictionary of numpy arrays satisfying this
                component's input properties.

        Returns:

            tendencies (dict), diagnostics (dict):
                * The heating and moistening tendencies
                * Any diagnostics associated.

        """
        self._set_fortran_constants()

        num_cols, num_levs = raw_state['air_temperature'].shape

        max_conv_level = num_levs - 3

        tendencies = initialize_numpy_arrays_with_properties(
            self.tendency_properties, raw_state, self.input_properties
        )
        diagnostics = initialize_numpy_arrays_with_properties(
            self.diagnostic_properties, raw_state, self.input_properties
        )

        q_sat = bolton_q_sat(
            raw_state['air_temperature'],
            raw_state['air_pressure'] * 100,
            self._Cpd, self._Cpv
        )

        _emanuel_convection.convect(
            num_levs,
            num_cols,
            max_conv_level,
            self._ntracers,
            timestep.total_seconds(),
            raw_state['air_temperature'],
            raw_state['specific_humidity'],
            q_sat,
            raw_state['eastward_wind'],
            raw_state['northward_wind'],
            raw_state['air_pressure'],
            raw_state['air_pressure_on_interface_levels'],
            diagnostics['convective_state'],
            diagnostics['convective_precipitation_rate'],
            diagnostics['convective_downdraft_velocity_scale'],
            diagnostics['convective_downdraft_temperature_scale'],
            diagnostics['convective_downdraft_specific_humidity_scale'],
            raw_state['cloud_base_mass_flux'],
            diagnostics['atmosphere_convective_available_potential_energy'],
            tendencies['air_temperature'],
            tendencies['specific_humidity'],
            tendencies['eastward_wind'],
            tendencies['northward_wind'])

        diagnostics['air_temperature_tendency_from_convection'][:] = (
            tendencies['air_temperature'] * 86400.)
        diagnostics['cloud_base_mass_flux'][:] = raw_state['cloud_base_mass_flux']
        return tendencies, diagnostics


import sys
import numpy as np
import os.path as op
import pandas as pd
from glob import glob
from sklearn.preprocessing import LabelEncoder
from tqdm import tqdm

sys.path.append('src')
from noise_ceiling import convert_doubles_to_single_labels

DU2EN = dict(
    Verrassing='surprise',
    Verdrietig='sadness',
    Bang='fear',
    Walging='disgust',
    Blij='happiness',
    Boos='anger'
)

le = LabelEncoder().fit(['happiness', 'surprise', 'fear', 'sadness', 'disgust', 'anger'])

paths = sorted(glob('data/ratings_complete/*expressive*'))
for path in tqdm(paths):
    df = pd.read_csv(path, sep='\t', index_col=0)
    #df = df.query("rating_type == @target")  # filter rating type
    df = df.query("rating != 'Geen van allen'")

    with pd.option_context('mode.chained_assignment', None):  # suppress stupid warning
        df.loc[:, 'rating'] = df.loc[:, 'rating'].replace(DU2EN)  # translate
        df_emo = df.query("rating_type == 'emotion'")
        df_emo.loc[:, 'rating'] = le.transform(df_emo['rating'])

    df_emo = convert_doubles_to_single_labels(df_emo['rating'], soft=False, keepdims=False)
    df_emo = pd.DataFrame(df_emo.values.argmax(axis=1), columns=['rating'], index=df_emo.index)
    df_emo['rating'] = le.inverse_transform(df_emo['rating'])
    df_emo = df_emo.rename({'rating': 'emotion'}, axis=1)

    df_tmp = df.query("rating_type == 'valence'")
    df_val = pd.DataFrame()
    for idx in df_emo.index:
        tmp = df_tmp.loc[idx, 'rating']
        if isinstance(tmp, pd.Series):
            val = df_tmp.loc[idx, 'rating'].astype(float).values.mean()
        else:
            val = tmp

        df_val.loc[idx, 'valence'] = val

    df_tmp = df.query("rating_type == 'arousal'")
    df_aro = pd.DataFrame()
    for idx in df_emo.index:
        tmp = df_tmp.loc[idx, 'rating']
        if isinstance(tmp, pd.Series):
            val = df_tmp.loc[idx, 'rating'].astype(float).values.mean()
        else:
            val = tmp

        df_aro.loc[idx, 'arousal'] = val

    df_all = pd.concat((df_emo.sort_index(), df_val.sort_index(), df_aro.sort_index()), axis=1)
    df_all.to_csv(f'data/ratings_reduced/{op.basename(path)}', sep='\t')


from tensorflow.keras.applications.mobilenet_v2 import preprocess_input
from tensorflow.keras.preprocessing.image import img_to_array
from tensorflow.keras.models import load_model
from imutils.video import VideoStream
import numpy as np
from util import mask_prediction
import imutils
import cv2
import os

face_detector = "./face_detector"
model_path = "borneel_mask_detector.model"

# load pretrained face detector
prototxtPath = os.path.sep.join([face_detector, "deploy.prototxt"])
weightsPath = os.path.sep.join([face_detector,"res10_300x300_ssd_iter_140000.caffemodel"])
face_net = cv2.dnn.readNet(prototxtPath, weightsPath)

# load mask detector model
mask_net = load_model(model_path)

video = VideoStream(0).start()

while True:
	frame = video.read()
	frame = imutils.resize(frame, width=800)

	(locs, preds) = mask_prediction(frame, face_net, mask_net)

	for (box, pred) in zip(locs, preds):
		(start_x, start_y, end_x, end_y) = box
		(mask, withoutMask) = pred

		if mask > withoutMask:
			label = "Mask"
			color = (0, 255, 0)
		else:
			label = "No mask"
			color = (0, 0, 255)

		label = "{}: {:.2f}%".format(label, max(mask, withoutMask) * 100)
		cv2.putText(frame, label, (start_x, start_y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.45, color, 2)
		cv2.rectangle(frame, (start_x, start_y), (end_x, end_y), color, 2)

	cv2.imshow("Frame", frame)
	key = cv2.waitKey(1) & 0xFF

	if key == 27:
		break

cv2.destroyAllWindows()
video.stop()


"""
SQuAD with Bidirectional Encoder Representations from Transformers

=========================================================================================

BERT base model exporter

@article{devlin2018bert,
  title={BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding},
  author={Devlin, Jacob and Chang, Ming- \
      Wei and Lee, Kenton and Toutanova, Kristina},
  journal={arXiv preprint arXiv:1810.04805},
  year={2018}
}
"""

# coding=utf-8

# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.
# pylint:disable=redefined-outer-name,logging-format-interpolation

import argparse
import collections
import json
import logging
import os
import io
import copy
import random
import time
import warnings
import ctypes

os.environ["MXNET_GPU_WORKER_NTHREADS"] = "1"
os.environ["MXNET_COPY_WORKER_NTHREADS"] = "1"

import numpy as np
import mxnet as mx

import gluonnlp as nlp
from gluonnlp.data import SQuAD
from data.qa import SQuADTransform, preprocess_dataset
from bert_qa_evaluate import get_F1_EM, predict, PredResult
from export import hybrid_bert, hybrid_bert_old

np.random.seed(6)
random.seed(6)
mx.random.seed(6)

send_lib = ctypes.CDLL('./libsend_data.so')

log = logging.getLogger('gluonnlp')
log.setLevel(logging.DEBUG)
formatter = logging.Formatter(
    fmt='%(levelname)s:%(name)s:%(asctime)s %(message)s', datefmt='%H:%M:%S')

parser = argparse.ArgumentParser(description='BERT QA model exporter for inference.')

parser.add_argument('--dtype',
                    type=str,
                    help='Type to use. Currently only float16 is supported.')

parser.add_argument('--model_parameters',
                    type=str,
                    default=None,
                    help='Model parameter file')

parser.add_argument('--bert_model',
                    type=str,
                    default='bert_12_768_12',
                    help='BERT model name. Currently only bert_12_768_12 is supported.')

parser.add_argument('--uncased',
                    action='store_false',
                    help='if not set, inputs are converted to lower case.')

parser.add_argument('--max_seq_length',
                    type=int,
                    default=384,
                    help='The maximum total input sequence length after WordPiece tokenization.'
                    'Sequences longer than this will be truncated, and sequences shorter '
                    'than this will be padded. default is 384')

parser.add_argument('--doc_stride',
                    type=int,
                    default=128,
                    help='When splitting up a long document into chunks, how much stride to '
                    'take between chunks. default is 128')

parser.add_argument('--max_query_length',
                    type=int,
                    default=64,
                    help='The maximum number of tokens for the question. Questions longer than '
                    'this will be truncated to this length. default is 64')

parser.add_argument('--gpu',
                    type=int,
                    default=0,
                    help='which gpu to use. GPU(0) is used if not set.')

parser.add_argument('--sentencepiece',
                    type=str,
                    default=None,
                    help='Path to the sentencepiece .model file for both tokenization and vocab.')

parser.add_argument('--gemms_compute_type',
                    type=str,
                    default='float16',
                    help='Precision or compute type to use in cublas forward GEMM. Default float16')

args = parser.parse_args()

console = logging.StreamHandler()
console.setLevel(logging.INFO)
console.setFormatter(formatter)
log.addHandler(console)

log.info(args)

model_name = args.bert_model
dataset_name = 'book_corpus_wiki_en_uncased'
model_parameters = args.model_parameters
lower = args.uncased

test_batch_size = 1
ctx = mx.gpu(args.gpu)

max_seq_length = args.max_seq_length
doc_stride = args.doc_stride
max_query_length = args.max_query_length

if max_seq_length <= max_query_length + 3:
    raise ValueError('The max_seq_length (%d) must be greater than max_query_length '
                     '(%d) + 3' % (max_seq_length, max_query_length))

# vocabulary and tokenizer
if args.sentencepiece:
    logging.info('loading vocab file from sentence piece model: %s', args.sentencepiece)
    if dataset_name:
        warnings.warn('Both --dataset_name and --sentencepiece are provided. '
                      'The vocabulary will be loaded based on --sentencepiece.')
    vocab = nlp.vocab.BERTVocab.from_sentencepiece(args.sentencepiece)
    dataset_name = None
else:
    vocab = None

use_fp16 = (args.dtype == 'float16')
if not use_fp16:
    raise ValueError("Currently only float16 is supported.")

hybrid_bert_old.init_fast_softmax()
orig_bert, _ = hybrid_bert_old.get_hybrid_model(
    name=model_name,
    dataset_name=dataset_name,
    vocab=vocab,
    pretrained=False,
    ctx=ctx,
    use_pooler=False,
    use_decoder=False,
    use_classifier=False,
    seq_length=args.max_seq_length,
    use_FP16=use_fp16)
orig_net = hybrid_bert_old.HybridBERTForQA(bert=orig_bert, use_FP16=use_fp16)
if model_parameters:
    nlp.utils.load_parameters(orig_net, model_parameters, ctx=ctx, cast_dtype=None)

hybrid_bert.init_fast_multiheadattn_and_softmax(args.gemms_compute_type)
hybrid_bert.detach_addbias_and_set_gemms_compute_type(args.gemms_compute_type)
bert, vocab = hybrid_bert.get_hybrid_model(
    name=model_name,
    dataset_name=dataset_name,
    vocab=vocab,
    pretrained=False,
    ctx=ctx,
    use_pooler=False,
    use_decoder=False,
    use_classifier=False,
    seq_length=args.max_seq_length,
    use_FP16=use_fp16)

def convert_arg_params(net_arg_params, loaded_arg_params, num_heads):
    for k, v in net_arg_params.items():
        k = k.replace('hybridbertencoder1', 'hybridbertencoder0')
        k = k.replace('hybridbertmodel1', 'hybridbertmodel0')
        k = k.replace('hybridbertforqa1', 'hybridbertforqa0')

        if k.endswith('ffn_1_bias_alone'):
            oldname = k[:-6]
            ffn_1_bias = loaded_arg_params[oldname].data().reshape(shape=(1, 1, -1))
            v.set_data(ffn_1_bias.astype(v.dtype))
        elif k.endswith('ffn_2_bias_alone'):
            oldname = k[:-6]
            ffn_2_bias = loaded_arg_params[oldname].data().reshape(shape=(1, 1, -1))
            v.set_data(ffn_2_bias.astype(v.dtype))
        elif k.endswith('proj_bias_alone'):
            oldname = k[:-6]
            proj_bias = loaded_arg_params[oldname].data().reshape(shape=(1, 1, -1))
            v.set_data(proj_bias.astype(v.dtype))
        elif k.endswith('proj_inweight'):
            assert k[:-13] + 'query_weight' in loaded_arg_params
            assert k[:-13] + 'key_weight' in loaded_arg_params
            assert k[:-13] + 'value_weight' in loaded_arg_params
            q_weight = loaded_arg_params[k[:-13] + 'query_weight'].data().reshape(shape=(num_heads, -1, 0),
                                                                                reverse=True)
            k_weight   = loaded_arg_params[k[:-13] + 'key_weight'].data().reshape(shape=(num_heads, -1, 0),
                                                                                reverse=True)
            v_weight = loaded_arg_params[k[:-13] + 'value_weight'].data().reshape(shape=(num_heads, -1, 0),
                                                                                reverse=True)
            all_weight = mx.nd.concat(q_weight, k_weight, v_weight, dim=-2)
            all_weight = mx.nd.reshape(all_weight, shape=(-1, 0), reverse=True)
            v.set_data(all_weight.astype(v.dtype))
        elif k.endswith('proj_inbias'):
            assert k[:-11] + 'query_bias' in loaded_arg_params
            assert k[:-11] + 'key_bias' in loaded_arg_params
            assert k[:-11] + 'value_bias' in loaded_arg_params
            q_bias = loaded_arg_params[k[:-11] + 'query_bias'].data().reshape(shape=(num_heads, -1),
                                                                              reverse=True)
            k_bias   = loaded_arg_params[k[:-11] + 'key_bias'].data().reshape(shape=(num_heads, -1),
                                                                              reverse=True)
            v_bias = loaded_arg_params[k[:-11] + 'value_bias'].data().reshape(shape=(num_heads, -1),
                                                                              reverse=True)
            all_bias = mx.nd.stack(q_bias, k_bias, v_bias, axis=1)
            all_bias = mx.nd.reshape(all_bias, shape=(-1))
            v.set_data(all_bias.astype(v.dtype))
        else:
            v.set_data(loaded_arg_params[k].data().astype(v.dtype))

net = hybrid_bert.HybridBERTForQA(bert=bert, use_FP16=use_fp16)
net.initialize(mx.init.Xavier(), ctx=ctx)
net.hybridize(static_alloc=True, static_shape=True)
if use_fp16:
    net.cast('float16')
if model_parameters:
    convert_arg_params(net.collect_params(), orig_net.collect_params(), 12)
if args.sentencepiece:
    tokenizer = nlp.data.BERTSPTokenizer(args.sentencepiece, vocab, lower=lower)
else:
    tokenizer = nlp.data.BERTTokenizer(vocab=vocab, lower=lower)

def _transposed_pad_arrs_to_max_length(arrs, pad_axis, pad_val, use_shared_mem, dtype):
    if isinstance(arrs[0], mx.nd.NDArray):
        dtype = arrs[0].dtype if dtype is None else dtype
        arrs = [arr.asnumpy() for arr in arrs]
    elif not isinstance(arrs[0], np.ndarray):
        arrs = [np.asarray(ele) for ele in arrs]
    else:
        dtype = arrs[0].dtype if dtype is None else dtype

    original_length = [ele.shape[pad_axis] for ele in arrs]
    max_size = max(original_length)

    ret_shape = list(arrs[0].shape)
    ret_shape[pad_axis] = max_size
    ret_shape = (ret_shape[0], len(arrs)) + tuple(ret_shape[1:])
    ret = np.full(shape=ret_shape, fill_value=pad_val, dtype=dtype)
    for i, arr in enumerate(arrs):
        if arr.shape[pad_axis] == max_size:
            ret[:,i] = arr
        else:
            slices = [slice(None) for _ in range(arr.ndim)]
            slices[pad_axis] = slice(0, arr.shape[pad_axis])
            if slices[pad_axis].start != slices[pad_axis].stop:
                slices = [slice(i, i + 1)] + slices
                ret[:, tuple(slices)] = arr
    ctx = mx.Context('cpu_shared', 0) if use_shared_mem else mx.cpu()
    ret = mx.nd.array(ret, ctx=ctx, dtype=dtype)
    original_length = mx.nd.array(original_length, ctx=ctx, dtype=np.int32)

    return ret, original_length

class TransposedPad(object):
    def __init__(self, axis=0, pad_val=None, ret_length=False, dtype=None):
        self._axis = axis
        assert isinstance(axis, int), 'axis must be an integer! ' \
                                      'Received axis=%s, type=%s.' % (str(axis),
                                                                      str(type(axis)))
        self._pad_val = 0 if pad_val is None else pad_val
        self._ret_length = ret_length
        self._dtype = dtype
        self._warned = False
        if pad_val is None:
            warnings.warn("padding value is not given and will be set automatically to 0")

    def __call__(self, data):
        if isinstance(data[0], mx.nd.NDArray) and not self._warned:
            self._warned = True
            warnings.warn("Using Pad with NDArrays is discouraged for speed reasons...")

        if isinstance(data[0], (mx.nd.NDArray, np.ndarray, list)):
            padded_arr, original_length = _transposed_pad_arrs_to_max_length(data, self._axis,
                                                                  self._pad_val, True,
                                                                  self._dtype)
            if self._ret_length:
                return padded_arr, original_length
            else:
                return padded_arr
        else:
            raise NotImplementedError

batchify_fn = nlp.data.batchify.Tuple(
    nlp.data.batchify.Stack(),
    TransposedPad(axis=0, pad_val=vocab[vocab.padding_token]),
    TransposedPad(axis=0, pad_val=vocab[vocab.padding_token]),
    nlp.data.batchify.Stack('float32'),
    nlp.data.batchify.Stack('float32'),
    nlp.data.batchify.Stack('float32'))

def send_data(arr_cpu, arr_gpu):
    cpu_handle = arr_cpu.handle
    gpu_handle = arr_gpu.handle
    if len(arr_cpu.shape) == 1:
        nbytes = 4 * arr_cpu.shape[0]
    elif len(arr_cpu.shape) == 2:
        nbytes = 4 * arr_cpu.shape[0] * arr_cpu.shape[1]
    ptr_cpu = ctypes.c_void_p()
    ptr_gpu = ctypes.c_void_p()
    mx.base._LIB.MXNDArrayGetData(arr_cpu.handle, ctypes.byref(ptr_cpu))
    mx.base._LIB.MXNDArrayGetData(arr_gpu.handle, ctypes.byref(ptr_gpu))
    send_lib.send_data(ptr_cpu, ptr_gpu, ctypes.c_size_t(nbytes))

def send_data_to_GPU(input_cpu, token_types_cpu, valid_length_cpu, input_gpu, token_types_gpu, valid_length_gpu):
    # Send data to the GPU using stream 0 in order to avoid
    # cudaStreamSynchronize call overhead that would happen
    # when naively copying the data to GPU via MXNet
    send_data(input_cpu, input_gpu)
    send_data(token_types_cpu, token_types_gpu)
    send_data(valid_length_cpu, valid_length_gpu)

def recv_data(arr_gpu, arr_cpu, nbytes, sync=False):
    gpu_handle = arr_gpu.handle
    ptr_gpu = ctypes.c_void_p()
    mx.base._LIB.MXNDArrayGetData(arr_gpu.handle, ctypes.byref(ptr_gpu))
    if sync:
        send_lib.recv_data_sync(arr_cpu, ptr_gpu, ctypes.c_size_t(nbytes))
    else:
        send_lib.recv_data_async(arr_cpu, ptr_gpu, ctypes.c_size_t(nbytes))

def recv_data_from_GPU(start_gpu, end_gpu, start_cpu, end_cpu):
    if use_fp16:
        nbytes = 2 * start_gpu.shape[0] * start_gpu.shape[1]
    else:
        nbytes = 4 * start_gpu.shape[0] * start_gpu.shape[1]
    recv_data(start_gpu, start_cpu, nbytes)
    recv_data(end_gpu, end_cpu, nbytes, sync=True)

def export():
    """Evaluate the model on validation dataset.
    """
    log.info('Loading dev data...')
    dev_data = SQuAD('dev', version='1.1')
    log.info('Number of records in dev data:{}'.format(len(dev_data)))

    dev_dataset = dev_data.transform(
        SQuADTransform(
            copy.copy(tokenizer),
            max_seq_length=max_seq_length,
            doc_stride=doc_stride,
            max_query_length=max_query_length,
            is_pad=False,
            is_training=False)._transform, lazy=False)

    dev_data_transform, _ = preprocess_dataset(
        dev_data, SQuADTransform(
            copy.copy(tokenizer),
            max_seq_length=max_seq_length,
            doc_stride=doc_stride,
            max_query_length=max_query_length,
            is_pad=True,
            is_training=False))
    log.info('The number of examples after preprocessing:{}'.format(
        len(dev_data_transform)))

    dev_dataloader = mx.gluon.data.DataLoader(
        dev_data_transform,
        batchify_fn=batchify_fn,
        num_workers=4, batch_size=test_batch_size,
        shuffle=False, last_batch='discard')

    total_iters=0
    total_time=0.0
    total_len = 0

    inputs_GPU = mx.nd.zeros((max_seq_length, test_batch_size), ctx=ctx)
    token_types_GPU = mx.nd.zeros((max_seq_length, test_batch_size), ctx=ctx)
    valid_length_GPU = mx.nd.zeros((test_batch_size,), ctx=ctx)

    if use_fp16:
        pred_start = np.zeros((test_batch_size, max_seq_length), dtype=np.float16)
        pred_end = np.zeros((test_batch_size, max_seq_length), dtype=np.float16)
    else:
        raise ValueError
        pred_start = np.zeros((test_batch_size, max_seq_length), dtype=np.float32)
        pred_end = np.zeros((test_batch_size, max_seq_length), dtype=np.float32)

    start_ptr = pred_start.ctypes.data_as(ctypes.c_void_p)
    end_ptr = pred_end.ctypes.data_as(ctypes.c_void_p)

    for data in dev_dataloader:
        example_ids, inputs, token_types, valid_length, _, _ = data
        mx.nd.waitall()
        tic = time.time()

        send_data_to_GPU(inputs, token_types, valid_length, inputs_GPU, token_types_GPU, valid_length_GPU)
        out1, out2 = net(inputs_GPU,
                         token_types_GPU,
                         valid_length_GPU)
        mx.nd.waitall()
        recv_data_from_GPU(out1, out2, start_ptr, end_ptr)

        toc = time.time()

        net.export('fp16_bert_' + str(max_seq_length), 0)
        break

if __name__ == '__main__':
    if model_parameters:
        export()
    else:
        raise RuntimeError("Need to provide model_parameters option")


# -*- coding: utf-8 -*-
# vim: tabstop=4 shiftwidth=4 softtabstop=4

#
# LICENSE
#
# Copyright (C) 2015-2019 GEM Foundation, G. Weatherill, M. Pagani
#
# The Hazard Modeller's Toolkit is free software: you can redistribute
# it and/or modify it under the terms of the GNU Affero General Public
# License as published by the Free Software Foundation, either version
# 3 of the License, or (at your option) any later version.
#
# You should have received a copy of the GNU Affero General Public License
# along with OpenQuake. If not, see <http://www.gnu.org/licenses/>
#
# DISCLAIMER
#
# The software Hazard Modeller's Toolkit (openquake.hmtk) provided herein
# is released as a prototype implementation on behalf of
# scientists and engineers working within the GEM Foundation (Global
# Earthquake Model).
#
# It is distributed for the purpose of open collaboration and in the
# hope that it will be useful to the scientific, engineering, disaster
# risk and software design communities.
#
# The software is NOT distributed as part of GEM's OpenQuake suite
# (https://www.globalquakemodel.org/tools-products) and must be considered as a
# separate entity. The software provided herein is designed and implemented
# by scientific staff. It is not developed to the design standards, nor
# subject to same level of critical review by professional software
# developers, as GEM's OpenQuake software suite.
#
# Feedback and contribution to the software is welcome, and can be
# directed to the hazard scientific staff of the GEM Model Facility
# (hazard@globalquakemodel.org).
#
# The Hazard Modeller's Toolkit (openquake.hmtk) is therefore distributed WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
#
# The GEM Foundation, and the authors of the software, assume no
# liability for use of the software.

"""
Python tools for calculating activity rates on a grid from a source model
"""
import numpy as np
from openquake.hazardlib.sourceconverter import SourceConverter
from openquake.hazardlib import nrml
from openquake.hazardlib.source.complex_fault import ComplexFaultSource
from openquake.hazardlib.source.characteristic import CharacteristicFaultSource
from openquake.hazardlib.source.simple_fault import SimpleFaultSource
from openquake.hazardlib.source.area import AreaSource
from openquake.hazardlib.source.point import PointSource
from openquake.hazardlib.geo.mesh import Mesh
from openquake.hazardlib.geo.polygon import Polygon

class RateGrid(object):
    """
    Class for calculation of activity rate grids

    :param float xspc:
        Longitude spacing of grid
    :param float yspc:
        Latitude spacing of grid
    :param float zspc:
        Depth spacing (km) of grid
    :param np.ndarray xlim:
        Longitude cell bounds
    :param np.ndarray ylim:
        Latitude cell bounds
    :param np.ndarray zlim:
        Depth cell bounds
    :param int nx:
        Number of longitude cells
    :param int ny:
        Number of latitude cells
    :param int nz:
        Number of depth cells
    :param list source_model:
        Seismic source mode
    :param np.ndarray rates:
        Activity rates
    :param float area_discretisation:
        Discretisation step (km) of area sources
    """

    def __init__(self, limits, sources, area_discretisation=10.):
        """
        Instantiate class with grid configurations
        :param list limits:
             Grid configuration [west, east, xspc, south, north, yspc,
                                 upper, lower, zspc]
        """
        self.xspc = limits[2]
        self.yspc = limits[5]
        self.zspc = limits[8]
        self.xlim = np.arange(limits[0], limits[1] + self.xspc, self.xspc)
        self.ylim = np.arange(limits[3], limits[4] + self.yspc, self.yspc)
        self.zlim = np.arange(limits[6], limits[7] + self.zspc, self.zspc)
        self.nx = len(self.xlim)
        self.ny = len(self.ylim)
        self.nz = len(self.zlim)
        self.source_model = sources
        self.rates = np.zeros([self.nx - 1, self.ny - 1, self.nz - 1],
                              dtype=float)
        self.area_discretisation = area_discretisation

    @classmethod
    def from_model_files(cls, limits, input_model, investigation_time=1.0,
                         simple_mesh_spacing=1.0, complex_mesh_spacing=5.0,
                         mfd_width=0.1, area_discretisation=10.0):
        """
        Reads the hazard model from a file

        :param list limits:
             Grid configuration [west, east, xspc, south, north, yspc,
                                 upper, lower, zspc]
        :param str input_model:
            Path to input source model
        :param float investigation_time:
            Investigation time of Poisson model
        :param float simple_mesh_spacing:
            Rupture mesh spacing of simple fault (km)
        :param float complex_mesh_spacing:
            Rupture mesh spacing of complex fault (km)
        :param float mfd_width:
            Spacing (in magnitude units) of MFD
        :param float area_discretisation:
            Spacing of discretisation of area source (km)
        """
        converter = SourceConverter(investigation_time,
                                    simple_mesh_spacing,
                                    complex_mesh_spacing,
                                    mfd_width,
                                    area_discretisation)
        sources = []
        for grp in nrml.to_python(input_model, converter):
            sources.extend(grp.sources)
        return cls(limits, sources, area_discretisation)

    def number_sources(self):
        """
        Returns the number of sources
        """
        return len(self.source_model)

    def get_rates(self, mmin, mmax=np.inf):
        """
        Returns the cumulative rates greater than Mmin

        :param float mmin:
            Minimum magnitude
        """
        nsrcs = self.number_sources()
        for iloc, source in enumerate(self.source_model):
            print("Source Number %s of %s, Name = %s, Typology = %s" % (
                iloc + 1,
                nsrcs,
                source.name,
                source.__class__.__name__))
            if isinstance(source, CharacteristicFaultSource):
                self._get_fault_rates(source, mmin, mmax)
            elif isinstance(source, ComplexFaultSource):
                self._get_fault_rates(source, mmin, mmax)
            elif isinstance(source, SimpleFaultSource):
                self._get_fault_rates(source, mmin, mmax)
            elif isinstance(source, AreaSource):
                self._get_area_rates(source, mmin, mmax)
            elif isinstance(source, PointSource):
                self._get_point_rates(source, mmin, mmax)
            else:
                print("Source type %s not recognised - skipping!" % source)
                continue

    def _get_point_location(self, location):
        """
        Returns the location in the output grid corresponding to the cell in
        which the epicentre lays

        :param location:
            Source hypocentre as instance of :class:
            openquake.hazardlib.geo.point.Point
        :returns:
            xloc - Location of longitude cell
            yloc - Location of latitude cell
        """
        if (location.longitude < self.xlim[0]) or\
                (location.longitude > self.xlim[-1]):
            return None, None
        xloc = int(((location.longitude - self.xlim[0]) / self.xspc) + 1E-7)
        if (location.latitude < self.ylim[0]) or\
                (location.latitude > self.ylim[-1]):
            return None, None
        yloc = int(((location.latitude - self.ylim[0]) / self.yspc) + 1E-7)
        return xloc, yloc

    def _get_point_rates(self, source, mmin, mmax=np.inf):
        """
        Adds the rates for a point source

        :param source:
            Point source as instance of :class:
            openquake.hazardlib.source.point.PointSource
        :param float mmin:
            Minimum Magnitude
        :param float mmax:
            Maximum Magnitude
        """
        xloc, yloc = self._get_point_location(source.location)
        if (xloc is None) or (yloc is None):
            return
        # Get annual rates
        annual_rate = source.get_annual_occurrence_rates()
        mags = np.array([val[0] for val in annual_rate])
        annual_rate = np.array([val[1] for val in annual_rate])
        idx = np.logical_and(mags >= mmin, mags < mmax)
        annual_rate = np.sum(annual_rate[idx])
        for hypo_depth in source.hypocenter_distribution.data:
            zloc = int((hypo_depth[1] - self.zlim[0]) / self.zspc)
            if (zloc < 0) or (zloc >= (self.nz - 1)):
                continue
            else:
                self.rates[xloc, yloc, zloc] += float(hypo_depth[0]) * \
                    annual_rate

    def _get_area_rates(self, source, mmin, mmax=np.inf):
        """
        Adds the rates from the area source by discretising the source
        to a set of point sources

        :param source:
            Area source as instance of :class:
            openquake.hazardlib.source.area.AreaSource
        """
        points = list(source)
        for point in points:
            self._get_point_rates(point, mmin, mmax)

    def _get_fault_rates(self, source, mmin, mmax=np.inf):
        """
        Adds the rates for a simple or complex fault source

        :param source:
            Fault source as instance of :class:
            openquake.hazardlib.source.simple_fault.SimpleFaultSource or
            openquake.hazardlib.source.complex_fault.ComplexFaultSource
        """
        for rupt in list(source.iter_ruptures()):
            valid_rupt = (rupt.mag >= mmin) and (rupt.mag < mmax)
            if not valid_rupt:
                continue
            grd = np.column_stack([rupt.surface.mesh.lons.flatten(),
                                   rupt.surface.mesh.lats.flatten(),
                                   rupt.surface.mesh.depths.flatten()])
            npts = np.shape(grd)[0]
            counter = np.histogramdd(grd,
                                     bins=[self.xlim, self.ylim, self.zlim]
                                     )[0]
            point_rate = rupt.occurrence_rate / float(npts)
            self.rates += (point_rate * counter)

class RatePolygon(RateGrid):
    """
    Calculates the rate of events within a polygon

    :param limits:
        Polygon as instance of :class: openquake.hazardlib.geo.polygon.Polygon
    :param float upper_depth:
        Upper seismic depth of the polygon (km)
    :param float lower_depth:
        Lower seismic depth of the polygon (km)
    :param list source_model:
        List of seismic sources
    :param float rates:
        Activity rate of polygon
    :param float area_discretisation:
        Discretisation spacing (km) of the area source
    """

    def __init__(self, limits, sources, area_discretisation=10.):
        """
        Instantiate class with grid configurations
        :param dict limits:
             Configuration as dictionary containing:
             * polygon - OpenQuake Polygon
             * uppper_depth - upper seismogenic depth (km)
             * lower_depth - lower seismogenic depth (km)
        """
        assert isinstance(limits["polygon"], Polygon)
        self.limits = limits["polygon"]
        self.upper_depth = limits["upper_depth"]
        self.lower_depth = limits["lower_depth"]
        self.source_model = sources
        self.rates = 0.0
        self.area_discretisation = area_discretisation

    def _get_point_rates(self, source, mmin, mmax=np.inf):
        """
        Adds the rates for a point source

        :param source:
            Point source as instance of :class:
            openquake.hazardlib.source.point.PointSource
        :param float mmin:
            Minimum Magnitude
        :param float mmax:
            Maximum Magnitude
        """
        src_mesh = Mesh.from_points_list([source.location])
        in_poly = self.limits.intersects(src_mesh)[0]
        if not in_poly:
            return
        else:
            for (mag, rate) in source.get_annual_occurrence_rates():
                if (mag < mmin) or (mag > mmax):
                    return
                else:
                    for (prob, depth) in source.hypocenter_distribution.data:
                        if (depth < self.upper_depth) or\
                                (depth > self.lower_depth):
                            continue
                        else:
                            self.rates += (prob * rate)

    def _get_fault_rates(self, source, mmin, mmax=np.inf):
        """
        Adds the rates for a simple or complex fault source

        :param source:
            Fault source as instance of :class:
            openquake.hazardlib.source.simple_fault.SimpleFaultSource or
            openquake.hazardlib.source.complex_fault.ComplexFaultSource
        """
        for rup in list(source.iter_ruptures()):
            if (rup.mag < mmin) or (rup.mag > mmax):
                # Magnitude outside search range
                continue
            depths = rup.surface.mesh.depths.flatten()
            # Generate simple mesh from surface
            rupt_mesh = Mesh(rup.surface.mesh.lons.flatten(),
                             rup.surface.mesh.lats.flatten(),
                             depths)
            # Mesh points in polygon
            in_poly = self.limits.intersects(rupt_mesh)
            in_depth = np.logical_and(depths >= self.upper_depth,
                                      depths <= self.lower_depth)
            idx = np.logical_and(in_poly, in_depth)
            if np.any(idx):
                node_rate = rup.occurrence_rate / float(len(depths))
                self.rates += (node_rate * np.sum(idx))