| #encoding:gbk 
 import pandas as pd
 import numpy as np
 import time
 import datetime
 import calendar
 from scipy import stats
 import tensorflow as tf
 import seaborn as sns
 import warnings
 warnings.filterwarnings("ignore")
 
 #sonnet
 from sonnet.python.modules.base import AbstractModule
 from sonnet.python.modules.basic import BatchApply, Linear, BatchFlatten
 from sonnet.python.modules.rnn_core import RNNCore
 from sonnet.python.modules.gated_rnn import LSTM
 from sonnet.python.modules.basic_rnn import DeepRNN
 
 from __future__ import absolute_import
 from __future__ import division
 from __future__ import print_function
 
 import functools
 from sonnet.python.modules import basic
 from sonnet.python.modules import rnn_core
 from sonnet.python.ops import nest
 
 
 def get_holdings(accountid,datatype):
 holdinglist={}
 resultlist=get_trade_detail_data(accountid,datatype,"POSITION")
 for obj in resultlist:
 holdinglist[obj.m_strInstrumentID+"."+obj.m_strExchangeID]=obj.m_nVolume
 return holdinglist
 
 def get_portfolio(accountid,datatype):
 result=0
 resultlist=get_trade_detail_data(accountid,datatype,"ACCOUNT")
 for obj in resultlist:
 result=obj.m_dAvailable
 return result
 
 def timetag_to_date(timetag, format):
 timetag = timetag/1000
 #time_local = time.localtime(timetag)
 return time.strftime(format,format)
 
 def init(ContextInfo):
 ContextInfo.index = '000016.SH'
 #ContextInfo.stocks = ContextInfo.get_sector('000300.SH')
 #ContextInfo.set_universe(ContextInfo.stocks)
 ContextInfo.stype = 'index'
 ContextInfo.accountID='110000035020'
 ContextInfo.isFirst = True
 
 
 
 
 
 # 参数
 ContextInfo.batch_size=1, #
 ContextInfo.hidden_size=100, # DNC控制器隐藏状态数量
 ContextInfo.memory_size=100, # 记忆矩阵大小
 ContextInfo.threshold=0.99, # ACT在时刻t循环运算截至阈值
 ContextInfo.pondering_coefficient = 1e-2, # 思考损失函数系数
 ContextInfo.num_reads=3 # DNC读头控制数量
 ContextInfo.num_writes=1 # DNC写头控制数量
 
 
 #预测参数
 ContextInfo.fit(5,learning_rate = 1e-1)#a.fit(5,learning_rate = 1e-1)
 # 参数
 ContextInfo.training_iters =1e2, # 训练次数
 ContextInfo.learning_rate = 1e-4, # 学习率
 ContextInfo.optimizer_epsilon = 1e-10, # 优化器参数建议保持原值
 ContextInfo.max_gard_norm = 50 # 优化器梯度防范参数建议保持原值
 
 
 
 ContextInfo.factors = ['Beta','btop',
 'etop','cetop','etp5','earning_yield',
 'agro']
 #,'rstr','lncap',
 #'净利率', '净资产收益率', '毛利率','资产收益率',
 #'资产负债率','市盈率','流通市值']
 '''
 ContextInfo.factors = ['Beta.beta','btop.btop',
 'EARNINGS_YIELD.etop','EARNINGS_YIELD.cetop','EARNINGS_YIELD.etp5','EARNINGS_YIELD.earning_yield',
 'GROWTH.agro',
 'MOMENTUM.rstr','NLSIZE.lncap',
 '净利率.考虑披露期延迟净利率', '净资产收益率.考虑披露期延迟净资产收益率', '毛利率.考虑披露期延迟毛利率','资产收益率.考虑披露期延迟资产收益率',
 '资产负债率.考虑披露期延迟资产负债率','市盈率.考虑披露期延迟市盈率','流通市值.流通市值']
 '''
 ContextInfo.financials = ['PERSHAREINDEX.du_return_on_equity', 'PERSHAREINDEX.sales_gross_profit', 'PERSHAREINDEX.inc_revenue_rate',
 'ERSHAREINDEX.du_profit_rate', 'PERSHAREINDEX.inc_net_profit_rate','PERSHAREINDEX.adjusted_net_profit_rate',
 'PERSHAREINDEX.inc_total_revenue_annual', 'PERSHAREINDEX.inc_net_profit_to_shareholders_annual', 'PERSHAREINDEX.adjusted_profit_to_profit_annual',
 'PERSHAREINDEX.equity_roe', 'PERSHAREINDEX.net_roe', 'PERSHAREINDEX.total_roe',
 'PERSHAREINDEX.gross_profit', 'PERSHAREINDEX.net_profit', 'PERSHAREINDEX.actual_tax_rate',
 'PERSHAREINDEX.gear_ratio', 'PERSHAREINDEX.inventory_turnover']
 
 ContextInfo.shift = 5 # 回溯时间步
 ContextInfo.training_iters = 1000 # 单周期训练次数
 ContextInfo.stop = 20 # 停下来查看loss的时间步
 ContextInfo.lr = 0.005 # 学习率
 ContextInfo.n_hidden_units = 100 # neurons in hidden layer
 ContextInfo.lstm_size = ContextInfo.n_hidden_units # 单层 lstm 的 hidden_units 数量
 ContextInfo.n_layers = 2 # lstm 层数
 
 
 def handlebar(ContextInfo):
 index = ContextInfo.index
 shift = ContextInfo.shift
 barpos = ContextInfo.barpos
 realtime = ContextInfo.get_bar_timetag(barpos)
 ContextInfo.current_dt = timetag_to_datetime(realtime,'%Y%m%d')
 today = ContextInfo.current_dt
 bkstart =  ContextInfo.start
 bkend = ContextInfo.end
 #bkstartday = substr(bkstart)
 #bkday = substr(bkend)
 #preDate1 = datetime.datetime.strptime(today, "%Y%m%d") + datetime.timedelta(days = -shift)
 #preDate =  preDate1.strftime('%Y%m%d')
 #preDate2 = datetime.datetime.strptime(today, "%Y%m%d") + datetime.timedelta(days = -1)
 #ContextInfo.previous_date =  preDate2.strftime('%Y%m%d')
 #print(preDate, type(preDate))
 index = ContextInfo.index
 #获取股票列表
 if ContextInfo.stype == 'index':
 ContextInfo.stocks = ContextInfo.get_sector(index, realtime)
 elif ContextInfo.stype == 'industry':
 ContextInfo.stocks = ContextInfo.get_industry(index)
 elif ContextInfo.stype == 'sector':
 ContextInfo.stocks = ContextInfo.get_stock_list_in_sector(index, realtime)
 else:
 ContextInfo.stocks = index
 ContextInfo.set_universe(ContextInfo.stocks)
 
 stockList = ContextInfo.stocks
 factorslist = ContextInfo.factors
 
 set_slip_fee(ContextInfo)
 
 print('时间戳获取中……')
 tradingday = ContextInfo.get_trading_dates('000001.SH', '', today, shift+1, '1d')
 shift_index_pred = list(tradingday).index(today) # 获取today对应的绝对日期排序数
 pred_days = tradingday[shift_index_pred - shift+1 : shift_index_pred+1] # 获取回溯需要的日期array
 
 start_date_pred = pred_days[0]
 end_date_pred = pred_days[-1]
 ContextInfo.previous_date =pred_days[-1]
 
 print('pred:', start_date_pred, end_date_pred)
 
 # 训练时间list
 shift_index_train = list(tradingday).index(today) -1 # 获取yesterday对应的绝对日期排序数
 train_days = tradingday[shift_index_train - shift+1 : shift_index_train+1 ]
 
 start_date_train = train_days[0]
 end_date_train = train_days[-1]
 #ContextInfo.previous_date =train_days[-1]
 
 print('train:',start_date_train, end_date_train, ContextInfo.previous_date)
 
 '''
 #剔除ST股
 st_data=get_extras('is_st',stockList, count = 1,end_date = date)
 stockList = [stock for stock in stockList if not st_data[stock][0]]
 
 #剔除停牌、新股及退市股票
 stockList=delect_stop(stockList,date,date)
 # stockList = stockList[:9]
 '''
 
 print('训练数据获取中……')
 x_tech_train = get_train_x(ContextInfo, stockList,factorslist,start_date_train, end_date_train)
 #print(x_tech_train)
 #x_fund_train = get_fund(ContextInfo, stockList, start_date_train, end_date_train)
 #print(x_fund_train)
 #x_train = pd.concat([x_tech_train, np.transpose(x_fund_train, (1,0,2))], axis =2)
 #x_train = pd.concat([x_tech_train, x_fund_train], axis=1)
 #print(x_train)
 x_train = x_tech_train
 y_train = get_train_y(ContextInfo, stockList, start_date_train, end_date_train)
 
 print('预测预备数据获取中……')
 x_tech_pred = get_train_x(ContextInfo, stockList,factorslist,start_date_pred, end_date_pred)
 #x_tech_pred = x_tech_train
 # x_fund_pred = get_fund(stockList, pred_days,industry_old_code,industry_new_code)
 x_pred = x_tech_pred
 print('单周期数据准备完成!!')
 
 # 参数
 training_iters = ContextInfo.training_iters # 单周期训练次数
 stop = ContextInfo.stop # 停下来查看loss的时间步
 lr = ContextInfo.lr # 学习率
 n_hidden_units = ContextInfo.n_hidden_units # neurons in hidden layer
 lstm_size = n_hidden_units # 单层 lstm 的 hidden_units 数量
 n_layers = ContextInfo.n_layers # lstm层数
 
 print('获取预测标的中……')
 #print(x_train)
 x_sub_train = x_train.get_values().astype(np.float32)#array(x_train.astype(np.float32))
 y_sub_train = y_train.get_values().astype(np.float32)#array(y_train.astype(np.float32))
 x_test = x_pred.get_values().astype(np.float32) #array(x_pred.astype(np.float32))
 
 # 参数
 n_inputs = (x_sub_train.shape[2]) # 输入参数维度
 n_steps = (x_sub_train.shape[1]) # time steps
 n_classes = y_sub_train.shape[2] # 分类元素
 n_layers = ContextInfo.n_layers # lstm层数
 lr = ContextInfo.lr # 学习率
 training_iters = ContextInfo.training_iters # 训练次数
 stop = ContextInfo.stop # 停止步数
 
 
 print('预测中……')
 pred = lstmtrain(x_sub_train, y_sub_train, x_pred, n_hidden_units,n_inputs, n_classes,n_steps,n_layers,lr, training_iters, stop)
 #print('pred:', pred)
 
 print('获取买入卖出池子中……')
 buy,sell,df = get_buy_sell(pred, y_train, stockList)
 buy_position = get_buy_position(df,buy)
 
 print('预测结果:',df)
 print('买入配资', buy_position)
 print('买入池子:',buy)
 print('卖出池子:',sell)
 
 ContextInfo.buy = list(buy_position.index)
 ContextInfo.sell = sell
 ContextInfo.buy_position = buy_position
 sell = list(sell)
 
 
 # 止盈止损池子
 today = ContextInfo.current_dt
 yesterday = ContextInfo.previous_date
 yesterday = str(yesterday)
 
 
 holdinglist = get_holdings(ContextInfo.accountID,'STOCK')
 #print('holdinglist', holdinglist)
 
 for stock in holdinglist:
 floating_return = get_floating_return(ContextInfo, stock,yesterday,today)
 if floating_return < -0.03 or floating_return > 0.1:
 list(sell).append(stock)
 
 ContextInfo.sell = list(sell)
 
 
 market_open(ContextInfo)
 
 
 # 【根据涨幅t1/t0倍数加权建仓】
 def market_open(ContextInfo):
 
 print('【开盘】(market_open):'+str(ContextInfo.current_dt))
 
 df_buy = ContextInfo.buy_position
 buy = ContextInfo.buy
 sell = ContextInfo.sell
 
 ContextInfo.holdings = get_holdings(ContextInfo.accountID,"STOCK")
 print(ContextInfo.holdings)
 # 获取每个标的的配资权重
 weight_for_stocks = {}
 for stock in df_buy.index:
 weight_for_stocks[stock] = list(df_buy.ix[stock])[-1]
 
 cash = get_portfolio(ContextInfo.accountID,'STOCK')
 # 买入股票
 for stock in ContextInfo.buy:
 if stock not in ContextInfo.holdings:
 order_value(stock, weight_for_stocks[stock]*cash, ContextInfo, ContextInfo.accountID)
 print('买入',stock)
 
 for stock in ContextInfo.sell:
 if stock in ContextInfo.holdings:
 order_target_percent(stock, 0, 'COMPETE', ContextInfo, ContextInfo.accountID)
 print('卖出',stock)
 
 
 # 设置滑点手续费
 def set_slip_fee(ContextInfo):
 # 将滑点设置为0
 ContextInfo.set_slippage(1, 0.0)
 # 根据不同的时间段设置手续费
 dt = ContextInfo.current_dt
 
 if dt >  '20130101': #datetime.datetime(2013,1, 1):
 commissionList = [0.0003,0.0013,0.0003, 0.0003, 0, 5]
 elif dt > '20110101': #datetime.datetime(2011,1, 1):
 commissionList = [0.001,0.002,0.0003, 0.0003, 0, 5]
 elif dt > '20090101':#datetime.datetime(2009,1, 1):
 commissionList = [0.002,0.003,0.0003, 0.0003, 0, 5]
 else:
 commissionList = [0.003,0.004,0.0003, 0.0003, 0, 5]
 ContextInfo.set_commission(0, commissionList)
 
 
 def get_fund(ContextInfo, stockList, start_date_pre, end_date_pre):
 fieldList = ['PERSHAREINDEX.du_return_on_equity', 'PERSHAREINDEX.sales_gross_profit', 'PERSHAREINDEX.inc_revenue_rate',
 'ERSHAREINDEX.du_profit_rate', 'PERSHAREINDEX.inc_net_profit_rate','PERSHAREINDEX.adjusted_net_profit_rate',
 'PERSHAREINDEX.inc_total_revenue_annual', 'PERSHAREINDEX.inc_net_profit_to_shareholders_annual', 'PERSHAREINDEX.adjusted_profit_to_profit_annual',
 'PERSHAREINDEX.equity_roe', 'PERSHAREINDEX.net_roe', 'PERSHAREINDEX.total_roe',
 'PERSHAREINDEX.gross_profit', 'PERSHAREINDEX.net_profit', 'PERSHAREINDEX.actual_tax_rate',
 'PERSHAREINDEX.gear_ratio', 'PERSHAREINDEX.inventory_turnover']
 x_fund = ContextInfo.get_financial_data(fieldList, stockList,start_date_pre, end_date_pre, report_type = 'announce_time')
 return x_fund
 
 # 训练数据获取
 # 单周期训练数据【x】
 def get_train_x(ContextInfo, stockList, factorslist, start_date_pre, end_date_pre):
 x_train = pd.DataFrame(columns=ContextInfo.factors)
 
 timeArray = time.strptime(start_date_pre, "%Y%m%d")
 start = time.strftime("%Y-%m-%d %H:%M:%S", timeArray)
 timeArrayend = time.strptime(end_date_pre, "%Y%m%d")
 end = time.strftime("%Y-%m-%d %H:%M:%S", timeArrayend)
 
 data = ext_data_range(factorslist[0],'000001.SH' ,start,end, ContextInfo)
 dfdate = pd.DataFrame.from_dict(data, orient='index', columns=['Beta'])
 dfdate.index.name = 'dates'
 del dfdate['Beta']
 #dfdate.index.map(substr)
 dfdate2 = dfdate.rename(index = substr)
 #print('*******:',dfdate2)
 # 训练数据【x】
 input_data1 = {}
 
 for stock in stockList:
 ddd = dfdate2
 for factor in factorslist:
 factor_data= ext_data_range(factor,stock ,start,end,ContextInfo)
 dffactor = pd.DataFrame.from_dict(factor_data, orient='index', columns=[factor])
 #dffactor.index.name = 'dates'
 #dffactor.index.map(substr)
 dffactor2 = dffactor.rename(index = substr)
 #print(dffactor2)
 ddd = ddd.join(dffactor2, on='dates')
 #print(ddd)
 
 dffund = ContextInfo.get_financial_data(ContextInfo.financials, [stock],start_date_pre, end_date_pre, report_type = 'announce_time')
 dfalldata = pd.concat([ddd, dffund], axis=1)
 #dfalldata = ddd
 #print(dfalldata)
 # 有些因子没有的,用别的近似代替
 #dfalldata.fillna(0, inplace = True)
 #input_data1[stock] = dfalldata
 
 # 去inf
 a = np.array(dfalldata)
 where_are_inf = np.isinf(a)
 a[where_are_inf] = 'nan'
 dfdata =pd.DataFrame(a, index=dfalldata.index, columns = dfalldata.columns)
 #print(dfalldata.columns)
 dfdata.fillna(0, inplace = True)
 data_pro = winsorize_and_standarlize(dfdata)
 #print('##############', data_pro)
 input_data1[stock] = data_pro
 
 
 #print('##############', type(input_data1), input_data1)
 #print('****************', input_data1)
 
 x_train = pd.Panel(input_data1)
 #print(type(x_train), x_train)
 return x_train
 
 # 单周期训练数据【y】
 def get_train_y(ContextInfo, stockList, start_date_last, end_date_last):
 
 # 训练数据【y】
 input_data = {}
 for i in stockList:
 data = ContextInfo.get_market_data(['close'], stock_code = ,
 start_time = start_date_last, end_time = end_date_last, skip_paused = True,
 period = ContextInfo.period, dividend_type = 'none', count = ContextInfo.shift)
 #print(data[data.columns[0]])
 data = data[data.columns[0]]
 input_data = pd.DataFrame(data)
 y_train = pd.Panel(input_data) # 训练因子数据
 
 return y_train
 
 
 # 获取买入卖出池子
 def get_buy_sell(pred,y_train,stockList):
 # 整合结果
 # 上一个交易日的收盘价
 df_y_t0 = dict(np.transpose((y_train),(1,0,2)))[list(dict(np.transpose((y_train),(1,0,2))).keys())[-1]]
 # 本交易日预测价格
 p = np.transpose(pred, (1,0,2))
 df_pred = pd.DataFrame(p[-1])
 df_pred.index = df_y_t0.index
 # 整合
 df = pd.concat([df_y_t0, df_pred], axis =1)
 df.columns = ['t0','pre_t1']
 
 # 获取预测标的池子
 diff1 = (df['pre_t1']-df['t0'])
 # 表格整理
 df1 = df.copy()
 df1['buy_decision'] = 0
 for i in range(len(df)):
 if list(diff1) > 0:
 df1.iloc[i,2] = True
 else :
 df1.iloc[i,2] = False
 
 # 买入池子
 buy = []
 for i in range(len(diff1)):
 if list(diff1) > 0 :
 buy.append(diff1.index)
 
 # 卖出池子
 sell = set(stockList) - set(buy)
 
 return buy,sell,df1
 
 # 获取标的日间浮动收益率
 def get_floating_return(ContextInfo, stock,yesterday,today):
 #print( [stock], str(yesterday), str(today), ContextInfo.period)
 a = ContextInfo.get_market_data(['close'], [stock], yesterday,today, True,ContextInfo.period, 'none', 2)
 past_p = list(a['close'])[0]
 current_p = list(a['close'])[-1]
 floating_return = current_p/past_p -1
 
 return floating_return
 
 # 【资金加权】
 def get_buy_position(df,buy):
 
 # 涨跌幅获取
 df['increase_pct'] = df['pre_t1']/df['t0']
 # 提取预测涨的股票
 df_buy = df.ix[buy]
 # 降序
 df_buy = df_buy.sort_values(by = ['increase_pct'], ascending = False)
 # 配资比率
 df_buy['buy%'] = df_buy['increase_pct']/sum(df['increase_pct'])
 
 return df_buy
 
 
 def substr(dtstr):
 data = dtstr[0:4]+dtstr[5:7]+dtstr[8:10]
 return data
 
 
 def winsorize_and_standarlize(data,qrange=[0.05,0.95],axis=0):
 '''
 input:
 data:Dataframe or series,输入数据
 qrange:list,list[0]下分位数,list[1],上分位数,极值用分位数代替
 '''
 if isinstance(data,pd.DataFrame):
 if axis == 0:
 q_down = data.quantile(qrange[0])
 q_up = data.quantile(qrange[1])
 index = data.index
 col = data.columns
 for n in col:
 data[n][data[n] > q_up[n]] = q_up[n]
 data[n][data[n] < q_down[n]] = q_down[n]
 data = (data - data.mean())/data.std()
 data = data.fillna(0)
 else:
 data = data.stack()
 data = data.unstack(0)
 q = data.quantile(qrange)
 index = data.index
 col = data.columns
 for n in col:
 data[n][data[n] > q[n]] = q[n]
 data = (data - data.mean())/data.std()
 data = data.stack().unstack(0)
 data = data.fillna(0)
 
 elif isinstance(data,pd.Series):
 name = data.name
 q = data.quantile(qrange)
 data[data>q] = q
 data = (data - data.mean())/data.std()
 return data
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 a = Classifier_DNC_BasicLSTM_L1(train_inputs, train_targets, train_gather_list)
 
 
 
 
 
 class Classifier_DNC_BasicLSTM_L1(object):
 
 def __init__(self,
 inputs,
 targets,
 gather_list=None,
 batch_size=1,
 hidden_size=10,
 memory_size=10,
 threshold=0.99,
 pondering_coefficient = 1e-2,
 num_reads=3,
 num_writes=1):
 
 self._tmp_inputs = inputs
 self._tmp_targets = targets
 self._in_length = inputs.shape[0]
 self._in_width = inputs.shape[2]
 self._out_length = targets.shape[0]
 self._out_width = targets.shape[2]
 self._batch_size = batch_size
 
 #
 self._sess = tf.InteractiveSession()
 
 self._inputs = tf.placeholder(dtype=tf.float32,
 shape=[self._in_length, self._batch_size, self._in_width],
 name='inputs')
 self._targets = tf.placeholder(dtype=tf.float32,
 shape=[self._out_length, self._batch_size, self._out_width],
 name='targets')
 
 act_core = DNCore_L1( hidden_size=hidden_size,
 memory_size=memory_size,
 word_size=self._in_width,
 num_read_heads=num_reads,
 num_write_heads=num_writes)
 self._InferenceCell = ACTCore(core=act_core,
 output_size=self._out_width,
 threshold=threshold,
 get_state_for_halting=self._get_hidden_state)
 
 self._initial_state = self._InferenceCell.initial_state(self._batch_size)
 
 tmp, act_final_cumul_state = \
 tf.nn.dynamic_rnn(cell=self._InferenceCell,
 inputs=self._inputs,
 initial_state=self._initial_state,
 time_major=True)
 act_output, (act_final_iteration, act_final_remainder) = tmp
 
 self._pred_outputs = act_output
 if gather_list is not None:
 out_sequences = tf.gather(act_output, gather_list)
 else:
 out_sequences = act_core
 
 pondering_cost = (act_final_iteration + act_final_remainder) * pondering_coefficient
 rnn_cost = tf.nn.softmax_cross_entropy_with_logits(
 labels=self._targets, logits=out_sequences)
 self._cost = tf.reduce_mean(rnn_cost) + tf.reduce_mean(pondering_cost)
 
 self._pred = tf.nn.softmax(out_sequences, dim=2)
 correct_pred = tf.equal(tf.argmax(self._pred,2), tf.argmax(self._targets,2))
 self._accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32))
 
 def _get_hidden_state(self, state):
 controller_state = state[0]
 next_state, next_cell = controller_state
 return next_state
 
 def fit(self,
 training_iters =1e2,
 learning_rate = 1e-4,
 optimizer_epsilon = 1e-10,
 max_gard_norm = 50):
 
 # Set up optimizer with global norm clipping.
 trainable_variables = tf.trainable_variables()
 grads, _ = tf.clip_by_global_norm(
 tf.gradients(self._cost, trainable_variables), max_gard_norm)
 global_step = tf.get_variable(
 name="global_step",
 shape=[],
 dtype=tf.int64,
 initializer=tf.zeros_initializer(),
 trainable=False,
 collections=[tf.GraphKeys.GLOBAL_VARIABLES, tf.GraphKeys.GLOBAL_STEP])
 
 optimizer = tf.train.RMSPropOptimizer(
 learning_rate=learning_rate, epsilon=optimizer_epsilon)
 self._train_step = optimizer.apply_gradients(
 zip(grads, trainable_variables), global_step=global_step)
 
 self._sess.run(tf.global_variables_initializer())
 for scope in range(np.int(training_iters)):
 _, loss, acc = self._sess.run([self._train_step, self._cost, self._accuracy],
 feed_dict = {self._inputs:self._tmp_inputs,
 self._targets:self._tmp_targets})
 print (scope, '  loss--', loss, '  acc--', acc)
 print ("Optimization Finished!")
 
 
 def close(self):
 self._sess.close()
 print ('结束进程,清理tensorflow内存/显存占用')
 
 
 def pred(self, inputs, gather_list=None):
 
 output_pred = self._pred_outputs
 if gather_list is not None:
 output_pred = tf.gather(output_pred, gather_list)
 probability = tf.nn.softmax(output_pred)
 classification = tf.argmax(probability, axis=-1)
 
 return self._sess.run([probability, classification],feed_dict = {self._inputs:inputs})
 
 
 
 class Classifier_DNC_BasicLSTM_L3(object):
 
 def __init__(self,
 inputs,
 targets,
 gather_list=None,
 batch_size=1,
 hidden_size=10,
 memory_size=10,
 threshold=0.99,
 pondering_coefficient = 1e-2,
 num_reads=3,
 num_writes=1):
 
 self._tmp_inputs = inputs
 self._tmp_targets = targets
 self._in_length = None
 self._in_width = inputs.shape[2]
 self._out_length = None
 self._out_width = targets.shape[2]
 self._batch_size = batch_size
 
 #
 self._sess = tf.InteractiveSession()
 
 self._inputs = tf.placeholder(dtype=tf.float32,
 shape=[self._in_length, self._batch_size, self._in_width],
 name='inputs')
 self._targets = tf.placeholder(dtype=tf.float32,
 shape=[self._out_length, self._batch_size, self._out_width],
 name='targets')
 
 act_core = DNCore_L3( hidden_size=hidden_size,
 memory_size=memory_size,
 word_size=self._in_width,
 num_read_heads=num_reads,
 num_write_heads=num_writes)
 self._InferenceCell = ACTCore(core=act_core,
 output_size=self._out_width,
 threshold=threshold,
 get_state_for_halting=self._get_hidden_state)
 
 self._initial_state = self._InferenceCell.initial_state(self._batch_size)
 
 tmp, act_final_cumul_state = \
 tf.nn.dynamic_rnn(cell=self._InferenceCell,
 inputs=self._inputs,
 initial_state=self._initial_state,
 time_major=True)
 act_output, (act_final_iteration, act_final_remainder) = tmp
 
 self._pred_outputs = act_output
 if gather_list is not None:
 out_sequences = tf.gather(act_output, gather_list)
 else:
 out_sequences = act_core
 
 pondering_cost = (act_final_iteration + act_final_remainder) * pondering_coefficient
 rnn_cost = tf.nn.softmax_cross_entropy_with_logits(
 labels=self._targets, logits=out_sequences)
 self._cost = tf.reduce_mean(rnn_cost) + tf.reduce_mean(pondering_cost)
 
 self._pred = tf.nn.softmax(out_sequences, dim=2)
 correct_pred = tf.equal(tf.argmax(self._pred,2), tf.argmax(self._targets,2))
 self._accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32))
 
 # 待处理函数
 def _get_hidden_state(self, state):
 controller_state, access_state, read_vectors = state
 layer_1, layer_2, layer_3 = controller_state
 L1_next_state, L1_next_cell = layer_1
 L2_next_state, L2_next_cell = layer_2
 L3_next_state, L3_next_cell = layer_3
 return tf.concat([L1_next_state, L2_next_state, L3_next_state], axis=-1)
 
 def fit(self,
 training_iters =1e2,
 learning_rate = 1e-4,
 optimizer_epsilon = 1e-10,
 max_gard_norm = 50):
 
 # Set up optimizer with global norm clipping.
 trainable_variables = tf.trainable_variables()
 grads, _ = tf.clip_by_global_norm(
 tf.gradients(self._cost, trainable_variables), max_gard_norm)
 global_step = tf.get_variable(
 name="global_step",
 shape=[],
 dtype=tf.int64,
 initializer=tf.zeros_initializer(),
 trainable=False,
 collections=[tf.GraphKeys.GLOBAL_VARIABLES, tf.GraphKeys.GLOBAL_STEP])
 
 optimizer = tf.train.RMSPropOptimizer(
 learning_rate=learning_rate, epsilon=optimizer_epsilon)
 self._train_step = optimizer.apply_gradients(
 zip(grads, trainable_variables), global_step=global_step)
 
 self._sess.run(tf.global_variables_initializer())
 for scope in range(np.int(training_iters)):
 _, loss, acc = self._sess.run([self._train_step, self._cost, self._accuracy],
 feed_dict = {self._inputs:self._tmp_inputs,
 self._targets:self._tmp_targets})
 print (scope, '  loss--', loss, '  acc--', acc)
 print ("Optimization Finished!")
 
 
 def close(self):
 self._sess.close()
 print ('结束进程,清理tensorflow内存/显存占用')
 
 
 def pred(self, inputs, gather_list=None):
 
 output_pred = self._pred_outputs
 if gather_list is not None:
 output_pred = tf.gather(output_pred, gather_list)
 probability = tf.nn.softmax(output_pred)
 classification = tf.argmax(probability, axis=-1)
 
 return self._sess.run([probability, classification],feed_dict = {self._inputs:inputs})
 
 
 
 
 
 
 # Content-based addressing
 class calculate_Content_based_addressing(AbstractModule):
 """
 Calculates the cosine similarity between a query and each word in memory, then
 applies a weighted softmax to return a sharp distribution.
 """
 
 def __init__(self,
 num_heads,
 word_size,
 epsilon = 1e-6,
 name='content_based_addressing'):
 
 """
 Initializes the module.
 
 Args:
 num_heads: number of memory write heads or read heads.
 word_size: memory word size.
 name: module name (default 'content_based_addressing')
 """
 super().__init__(name=name) # 调用父类初始化
 self._num_heads = num_heads
 self._word_size = word_size
 self._epsilon = epsilon
 
 
 def _Clip_L2_norm(self, tensor, axis=2):
 """
 计算L2范数,为余弦相似性计算公式分母,这里进行数值平稳化处理
 """
 quadratic_sum = tf.reduce_sum(tf.multiply(tensor, tensor), axis=axis, keep_dims=True)
 #return tf.max(tf.sqrt(quadratic_sum + self._epsilon), self._epsilon)
 return tf.sqrt(quadratic_sum + self._epsilon)
 
 
 def _Calculate_cosine_similarity(self, keys, memory):
 
 """
 Args:
 memory: A 3-D tensor of shape [batch_size, memory_size, word_size]
 keys: A 3-D tensor of shape [batch_size, num_heads, word_size]
 Returns:
 cosine_similarity: A 3-D tensor of shape `[batch_size, num_heads, memory_size]`.
 """
 
 matmul = tf.matmul(keys, memory, adjoint_b=True)
 memory_norm = self._Clip_L2_norm(memory, axis=2)
 keys_norm = self._Clip_L2_norm(keys, axis=2)
 cosine_similarity = matmul / (tf.matmul(keys_norm, memory_norm, adjoint_b=True) + self._epsilon)
 return cosine_similarity
 
 
 def _build(self, memory, keys, strengths):
 """
 Connects the CosineWeights module into the graph.
 
 Args:
 memory: A 3-D tensor of shape `[batch_size, memory_size, word_size]`.
 keys: A 3-D tensor of shape `[batch_size, num_heads, word_size]`.
 strengths: A 2-D tensor of shape `[batch_size, num_heads]`.
 
 Returns:
 cosine_similarity: A 3-D tensor of shape `[batch_size, num_heads, memory_size]`.
 content_weighting: Weights tensor of shape `[batch_size, num_heads, memory_size]`.
 """
 cosine_similarity = self._Calculate_cosine_similarity(keys=keys, memory=memory)
 transformed_strengths = tf.expand_dims(strengths, axis=-1)
 sharp_activations = cosine_similarity * transformed_strengths
 
 softmax = BatchApply(module_or_op=tf.nn.softmax)
 return softmax(sharp_activations)
 
 #Dynamic_memory_allocation
 class update_Dynamic_memory_allocation(RNNCore):
 """
 Memory usage that is increased by writing and decreased by reading.
 
 This module is a pseudo-RNNCore whose state is a tensor with values in
 the range [0, 1] indicating the usage of each of `memory_size` memory slots.
 
 The usage is:
 
 *   Increased by writing, where usage is increased towards 1 at the write
 addresses.
 *   Decreased by reading, where usage is decreased after reading from a
 location when free_gates is close to 1.
 """
 
 def __init__(self,
 memory_size,
 epsilon = 1e-6,
 name='dynamic_memory_allocation'):
 
 """Creates a module for dynamic memory allocation.
 
 Args:
 memory_size: Number of memory slots.
 name: Name of the module.
 """
 super().__init__(name=name)
 self._memory_size = memory_size
 self._epsilon = epsilon
 
 
 def _build(self,
 prev_usage,
 prev_write_weightings,
 free_gates,
 prev_read_weightings,
 write_gates,
 num_writes):
 
 usage = self._update_usage_vector(prev_usage,
 prev_write_weightings,
 free_gates,
 prev_read_weightings)
 
 allocation_weightings = \
 self._update_allocation_weightings(usage,
 write_gates,
 num_writes)
 
 return usage, allocation_weightings
 
 
 def _update_usage_vector(self,
 prev_usage,
 prev_write_weightings,
 free_gates,
 prev_read_weightings):
 """
 The usage is:
 
 *   Increased by writing, where usage is increased towards 1 at the write
 addresses.
 *   Decreased by reading, where usage is decreased after reading from a
 location when free_gates is close to 1.
 
 Args:
 prev_usage: tensor of shape `[batch_size, memory_size]` giving
 usage u_{t - 1} at the previous time step, with entries in range [0, 1].
 
 prev_write_weightings: tensor of shape `[batch_size, num_writes, memory_size]`
 giving write weights at previous time step.
 
 free_gates: tensor of shape `[batch_size, num_reads]` which indicates
 which read heads read memory that can now be freed.
 
 prev_read_weightings: tensor of shape `[batch_size, num_reads, memory_size]`
 giving read weights at previous time step.
 
 Returns:
 usage: tensor of shape `[batch_size, memory_size]` representing updated memory usage.
 """
 prev_write_weightings = tf.stop_gradient(prev_write_weightings)
 usage = self._Calculate_usage_vector(prev_usage, prev_write_weightings)
 retention = self._Calculate_retention_vector(free_gates, prev_read_weightings)
 return usage * retention
 
 
 def _Calculate_usage_vector(self, prev_usage, prev_write_weightings):
 """
 注意这里usage更新使用上一个时间步的数据更新
 这个函数是特别添加处理多个写头的,
 这个函数计算在写头操作之后记忆矩阵的使用情况usage
 
 Calcualtes the new usage after writing to memory.
 
 Args:
 prev_usage: tensor of shape `[batch_size, memory_size]`.
 write_weightings: tensor of shape `[batch_size, num_writes, memory_size]`.
 
 Returns:
 New usage, a tensor of shape `[batch_size, memory_size]`.
 """
 with tf.name_scope('usage_after_write'):
 # Calculate the aggregated effect of all write heads
 fit_prev_write_weightings = 1 - \
 tf.reduce_prod(1 - prev_write_weightings, axis=[1])
 
 usage_without_free = \
 prev_usage + fit_prev_write_weightings - \
 prev_usage * fit_prev_write_weightings
 
 return usage_without_free
 
 
 def _Calculate_retention_vector(self, free_gates, prev_read_weightings):
 """
 The memory retention vector phi_t represents by how much each location
 will not be freed by the gates.
 
 Args:
 free_gates: tensor of shape `[batch_size, num_reads]` with entries in the
 range [0, 1] indicating the amount that locations read from can be
 freed.
 
 prev_write_weightings: tensor of shape `[batch_size, num_writes, memory_size]`.
 Returns:
 retention vector: [batch_size, memory_size]
 """
 with tf.name_scope('usage_after_read'):
 free_gates = tf.expand_dims(free_gates, axis=-1)
 
 retention_vector = tf.reduce_prod(
 1 - free_gates * prev_read_weightings,
 axis=[1], name='retention')
 
 return retention_vector
 
 
 def _update_allocation_weightings(self, usage, write_gates, num_writes):
 """
 Calculates freeness-based locations for writing to.
 
 This finds unused memory by ranking the memory locations by usage, for each
 write head. (For more than one write head, we use a "simulated new usage"
 which takes into account the fact that the previous write head will increase
 the usage in that area of the memory.)
 
 Args:
 usage: A tensor of shape `[batch_size, memory_size]` representing
 current memory usage.
 
 write_gates: A tensor of shape `[batch_size, num_writes]` with values in
 the range [0, 1] indicating how much each write head does writing
 based on the address returned here (and hence how much usage
 increases).
 
 num_writes: The number of write heads to calculate write weights for.
 
 Returns:
 tensor of shape `[batch_size, num_writes, memory_size]` containing the
 freeness-based write locations. Note that this isn't scaled by `write_gate`;
 this scaling must be applied externally.
 """
 with tf.name_scope('update_allocation'):
 write_gates = tf.expand_dims(write_gates, axis=-1)
 allocation_weightings = []
 for i in range(num_writes):
 allocation_weightings.append(
 self._Calculate_allocation_weighting(usage))
 # update usage to take into account writing to this new allocation
 usage += ((1-usage) * write_gates[:,i,:] * allocation_weightings)
 return tf.stack(allocation_weightings, axis=1)
 
 
 def _Calculate_allocation_weighting(self, usage):
 
 """
 Computes allocation by sorting `usage`.
 
 This corresponds to the value a = a_t[\phi_t[j]] in the paper.
 
 Args:
 usage: tensor of shape `[batch_size, memory_size]` indicating current
 memory usage. This is equal to u_t in the paper when we only have one
 write head, but for multiple write heads, one should update the usage
 while iterating through the write heads to take into account the
 allocation returned by this function.
 
 Returns:
 Tensor of shape `[batch_size, memory_size]` corresponding to allocation.
 """
 with tf.name_scope('allocation'):
 # Ensure values are not too small prior to cumprod.
 usage = self._epsilon + (1 - self._epsilon) * usage
 non_usage = 1 - usage
 
 sorted_non_usage, indices = tf.nn.top_k(
 non_usage, k = self._memory_size, name='sort')
 
 sorted_usage = 1 - sorted_non_usage
 prod_sorted_usage = tf.cumprod(sorted_usage, axis=1, exclusive=True)
 
 sorted_allocation_weighting = sorted_non_usage * prod_sorted_usage
 
 # This final line "unsorts" sorted_allocation, so that the indexing
 # corresponds to the original indexing of `usage`.
 inverse_indices = self._batch_invert_permutation(indices)
 allocation_weighting = self._batch_gather(
 sorted_allocation_weighting, inverse_indices)
 
 return allocation_weighting
 
 
 def _batch_invert_permutation(self, permutations):
 
 """
 Returns batched `tf.invert_permutation` for every row in `permutations`.
 """
 
 with tf.name_scope('batch_invert_permutation', values=[permutations]):
 unpacked = tf.unstack(permutations, axis=0)
 
 inverses = [tf.invert_permutation(permutation) for permutation in unpacked]
 return tf.stack(inverses, axis=0)
 
 
 def _batch_gather(self, values, indices):
 """Returns batched `tf.gather` for every row in the input."""
 
 with tf.name_scope('batch_gather', values=[values, indices]):
 unpacked = zip(tf.unstack(values), tf.unstack(indices))
 result = [tf.gather(value, index) for value, index in unpacked]
 return tf.stack(result)
 
 @property
 def state_size(self):
 pass
 
 @property
 def output_size(self):
 pass
 
 #Temporal_memory_linkage
 class update_Temporal_memory_linkage(RNNCore):
 """
 Keeps track of write order for forward and backward addressing.
 
 This is a pseudo-RNNCore module, whose state is a pair `(link,
 precedence_weights)`, where `link` is a (collection of) graphs for (possibly
 multiple) write heads (represented by a tensor with values in the range
 [0, 1]), and `precedence_weights` records the "previous write locations" used
 to build the link graphs.
 
 The function `directional_read_weights` computes addresses following the
 forward and backward directions in the link graphs.
 """
 def __init__(self,
 memory_size,
 num_writes,
 name='temporal_memory_linkage'):
 
 """
 Construct a TemporalLinkage module.
 
 Args:
 memory_size: The number of memory slots.
 num_writes: The number of write heads.
 name: Name of the module.
 """
 super().__init__(name=name)
 self._memory_size = memory_size
 self._num_writes = num_writes
 
 
 def _build(self,
 prev_link,
 prev_precedence_weightings,
 prev_read_weightings,
 write_weightings):
 """
 Calculate the updated linkage state given the write weights.
 
 Args:
 prev_links: A tensor of shape `[batch_size, num_writes, memory_size, memory_size]`
 representing the previous link graphs for each write head.
 
 prev_precedence_weightings: A tensor of shape `[batch_size, num_writes, memory_size]`
 containing the previous precedence weights.
 
 write_weightings: A tensor of shape `[batch_size, num_writes, memory_size]`
 containing the memory addresses of the different write heads.
 
 Returns:
 link:  A tensor of shape `[batch_size, num_writes, memory_size, memory_size]`
 precedence_weightings: A tensor of shape `[batch_size, num_writes, memory_size]`
 
 """
 link = self._update_link_matrix(
 prev_link, prev_precedence_weightings, write_weightings)
 
 precedence_weightings = \
 self._update_precedence_weightings(
 prev_precedence_weightings, write_weightings)
 
 forward_weightings = \
 self._Calculate_directional_read_weightings(
 link, prev_read_weightings, forward=True)
 
 backward_weightings = \
 self._Calculate_directional_read_weightings(
 link, prev_read_weightings, forward=False)
 
 return link, precedence_weightings, forward_weightings, backward_weightings
 
 
 def _update_link_matrix(self,
 prev_link,
 prev_precedence_weightings,
 write_weightings):
 """
 Calculates the new link graphs.
 
 For each write head, the link is a directed graph (represented by a matrix
 with entries in range [0, 1]) whose vertices are the memory locations, and
 an edge indicates temporal ordering of writes.
 
 Args:
 prev_links: A tensor of shape `[batch_size, num_writes, memory_size, memory_size]`
 representing the previous link graphs for each write head.
 
 prev_precedence_weights: A tensor of shape `[batch_size, num_writes, memory_size]`
 which is the previous "aggregated" write weights for each write head.
 
 write_weightings: A tensor of shape `[batch_size, num_writes, memory_size]`
 containing the new locations in memory written to.
 
 Returns:
 A tensor of shape `[batch_size, num_writes, memory_size, memory_size]`
 containing the new link graphs for each write head.
 """
 
 with tf.name_scope('link'):
 
 write_weightings_i = tf.expand_dims(write_weightings, axis=3)
 write_weightings_j = tf.expand_dims(write_weightings, axis=2)
 prev_link_scale = 1 - write_weightings_i - write_weightings_j
 remove_old_link = prev_link_scale * prev_link
 
 prev_precedence_weightings_j = tf.expand_dims(
 prev_precedence_weightings, axis=2)
 add_new_link = write_weightings_i * prev_precedence_weightings_j
 
 link = remove_old_link + add_new_link
 
 #Return the link with the diagonal set to zero, to remove self-looping edges.
 batch_size = prev_link.get_shape()[0].value
 mask = tf.zeros(shape=[batch_size, self._num_writes, self._memory_size],
 dtype=prev_link.dtype)
 
 fit_link = tf.matrix_set_diag(link, diagonal=mask)
 return fit_link
 
 
 def _update_precedence_weightings(self,
 prev_precedence_weightings,
 write_weightings):
 """
 Calculates the new precedence weights given the current write weights.
 
 The precedence weights are the "aggregated write weights" for each write
 head, where write weights with sum close to zero will leave the precedence
 weights unchanged, but with sum close to one will replace the precedence
 weights.
 
 Args:
 prev_precedence_weightings: A tensor of shape `[batch_size, num_writes, memory_size]`
 containing the previous precedence weights.
 
 write_weightings: A tensor of shape `[batch_size, num_writes, memory_size]`
 containing the new write weights.
 
 Returns:
 A tensor of shape `[batch_size, num_writes, memory_size]`
 containing the new precedence weights.
 """
 with tf.name_scope('precedence_weightings'):
 sum_writing = tf.reduce_sum(write_weightings, axis=2, keep_dims=True)
 
 precedence_weightings = \
 (1 - sum_writing) * prev_precedence_weightings + write_weightings
 
 return precedence_weightings
 
 
 def _Calculate_directional_read_weightings(self,
 link,
 prev_read_weightings,
 forward):
 """
 Calculates the forward or the backward read weightings.
 
 For each read head (at a given address), there are `num_writes` link graphs to follow.
 Thus this function computes a read address for each of the
 `num_reads * num_writes` pairs of read and write heads.
 
 Args:
 link: tensor of shape `[batch_size, num_writes, memory_size, memory_size]`
 representing the link graphs L_t.
 
 prev_read_weightsing: tensor of shape `[batch_size, num_reads, memory_size]`
 containing the previous read weights w_{t-1}^r.
 
 forward: Boolean indicating whether to follow the "future" direction in
 the link graph (True) or the "past" direction (False).
 
 Returns:
 tensor of shape `[batch_size, num_reads, num_writes, memory_size]`
 
 Note: We calculate the forward and backward directions for each pair of
 read and write heads; hence we need to tile the read weights and do a
 sort of "outer product" to get this.
 """
 with tf.name_scope('directional_read_weightings'):
 # We calculate the forward and backward directions for each pair of
 # read and write heads; hence we need to tile the read weights and do a
 # sort of "outer product" to get this.
 expanded_read_weightings = \
 tf.stack([prev_read_weightings] * self._num_writes, axis=1)
 directional_weightings = tf.matmul(expanded_read_weightings, link, adjoint_b=forward)
 # Swap dimensions 1, 2 so order is [batch, reads, writes, memory]:
 return tf.transpose(directional_weightings, perm=[0,2,1,3])
 
 # MemoryAccess
 class MemoryAccess(RNNCore):
 """
 Access module of the Differentiable Neural Computer.
 
 This memory module supports multiple read and write heads. It makes use of:
 
 *   `update_Temporal_memory_linkage` to track the temporal
 ordering of writes in memory for each write head.
 
 *   `update_Dynamic_memory_allocation` for keeping track of
 memory usage, where usage increase when a memory location is
 written to, and decreases when memory is read from that
 the controller says can be freed.
 
 Write-address selection is done by an interpolation between content-based
 lookup and using unused memory.
 
 Read-address selection is done by an interpolation of content-based lookup
 and following the link graph in the forward or backwards read direction.
 """
 
 def __init__(self,
 memory_size = 128,
 word_size = 20,
 num_reads = 1,
 num_writes = 1,
 name='memory_access'):
 
 """
 Creates a MemoryAccess module.
 
 Args:
 memory_size: The number of memory slots (N in the DNC paper).
 word_size: The width of each memory slot (W in the DNC paper)
 num_reads: The number of read heads (R in the DNC paper).
 num_writes: The number of write heads (fixed at 1 in the paper).
 name: The name of the module.
 """
 super().__init__(name=name)
 self._memory_size = memory_size
 self._word_size = word_size
 self._num_reads = num_reads
 self._num_writes = num_writes
 
 self._write_content_mod = calculate_Content_based_addressing(
 num_heads = self._num_writes,
 word_size = self._word_size,
 name = 'write_content_based_addressing')
 
 self._read_content_mod = calculate_Content_based_addressing(
 num_heads = self._num_reads,
 word_size = self._word_size,
 name = 'read_content_based_addressing')
 
 self._temporal_linkage = update_Temporal_memory_linkage(
 memory_size = self._memory_size,
 num_writes = self._num_writes)
 
 self._dynamic_allocation = update_Dynamic_memory_allocation(
 memory_size = self._memory_size)
 
 
 def _build(self, interface_vector, prev_state):
 """
 Connects the MemoryAccess module into the graph.
 
 Args:
 inputs: tensor of shape `[batch_size, input_size]`.
 This is used to control this access module.
 
 prev_state: Instance of `AccessState` containing the previous state.
 
 Returns:
 A tuple `(output, next_state)`, where `output` is a tensor of shape
 `[batch_size, num_reads, word_size]`, and `next_state` is the new
 `AccessState` named tuple at the current time t.
 """
 tape = self._Calculate_interface_parameters(interface_vector)
 
 prev_memory,\
 prev_read_weightings,\
 prev_write_weightings,\
 prev_precedence_weightings,\
 prev_link,\
 prev_usage = prev_state
 
 # 更新写头
 write_weightings,\
 usage = \
 self._update_write_weightings(tape,
 prev_memory,
 prev_usage,
 prev_write_weightings,
 prev_read_weightings)
 
 # 更新记忆
 memory = self._update_memory(prev_memory,
 write_weightings,
 tape['erase_vectors'],
 tape['write_vectors'])
 
 # 更新读头
 read_weightings,\
 link,\
 precedence_weightings= \
 self._update_read_weightings(tape,
 memory,
 write_weightings,
 prev_read_weightings,
 prev_precedence_weightings,
 prev_link)
 
 read_vectors = tf.matmul(read_weightings, memory)
 
 state = (memory,
 read_weightings,
 write_weightings,
 precedence_weightings,
 link,
 usage)
 
 return read_vectors, state
 
 
 def _update_write_weightings(self,
 tape,
 prev_memory,
 prev_usage,
 prev_write_weightings,
 prev_read_weightings):
 """
 Calculates the memory locations to write to.
 
 This uses a combination of content-based lookup and finding an unused
 location in memory, for each write head.
 
 Args:
 tape: Collection of inputs to the access module, including controls for
 how to chose memory writing, such as the content to look-up and the
 weighting between content-based and allocation-based addressing.
 
 memory: A tensor of shape  `[batch_size, memory_size, word_size]`
 containing the current memory contents.
 
 usage: Current memory usage, which is a tensor of shape
 `[batch_size, memory_size]`, used for allocation-based addressing.
 
 Returns:
 tensor of shape `[batch_size, num_writes, memory_size]`
 indicating where to write to (if anywhere) for each write head.
 """
 with tf.name_scope('update_write_weightings', \
 values=[tape, prev_memory, prev_usage]):
 
 write_content_weightings = \
 self._write_content_mod(
 prev_memory,
 tape['write_content_keys'],
 tape['write_content_strengths'])
 
 usage, write_allocation_weightings = \
 self._dynamic_allocation(
 prev_usage,
 prev_write_weightings,
 tape['free_gates'],
 prev_read_weightings,
 tape['write_gates'],
 self._num_writes)
 
 allocation_gates = tf.expand_dims(tape['allocation_gates'], axis=-1)
 write_gates = tf.expand_dims(tape['write_gates'], axis=-1)
 
 write_weightings = write_gates * \
 (allocation_gates * write_allocation_weightings + \
 (1 - allocation_gates) * write_content_weightings)
 
 return write_weightings, usage
 
 
 def _update_memory(self,
 prev_memory,
 write_weightings,
 erase_vectors,
 write_vectors):
 """
 Args:
 prev_memory: 3-D tensor of shape `[batch_size, memory_size, word_size]`.
 write_weightings: 3-D tensor `[batch_size, num_writes, memory_size]`.
 erase_vectors: 3-D tensor `[batch_size, num_writes, word_size]`.
 write_vectors: 3-D tensor `[batch_size, num_writes, word_size]`.
 
 Returns:
 memory: 3-D tensor of shape `[batch_size, num_writes, word_size]`.
 """
 with tf.name_scope('erase_old_memory', \
 values=[prev_memory,
 write_weightings,
 erase_vectors]):
 
 expand_write_weightings = \
 tf.expand_dims(write_weightings, axis=3)
 
 expand_erase_vectors = \
 tf.expand_dims(erase_vectors, axis=2)
 
 # 这里有多个写头,需要使用累成处理多个写头
 erase_gates = \
 expand_write_weightings * expand_erase_vectors
 
 retention_gate = \
 tf.reduce_prod(1 - erase_gates, axis=[1])
 
 retention_memory = prev_memory * retention_gate
 
 with tf.name_scope('additive_new_memory', \
 values=[retention_memory,
 write_weightings,
 write_vectors]):
 
 memory = retention_memory + \
 tf.matmul(write_weightings, write_vectors, adjoint_a=True)
 
 return memory
 
 
 def _Calculate_interface_parameters(self, interface_vector):
 """
 Interface parameters.
 Before being used to parameterize the memory interactions,
 the individual components are then processed with various
 functions to ensure that they lie in the correct domain.
 """
 # read_keys: [batch_size, num_reads, word_size]
 read_keys = Linear(
 output_size= self._num_reads * self._word_size,
 name='read_keys')(interface_vector)
 read_keys = tf.reshape(
 read_keys, shape=[-1, self._num_reads, self._word_size])
 
 # write_keys: [batch_size, num_writes, word_size]
 write_keys = Linear(
 output_size= self._num_writes * self._word_size,
 name= 'write_keys')(interface_vector)
 write_keys = tf.reshape(
 write_keys, shape=[-1, self._num_writes, self._word_size])
 
 
 # read_strengths: [batch_size, num_reads]
 read_strengths = Linear(
 output_size= self._num_reads,
 name= 'read_strengths')(interface_vector)
 read_strengths = 1 + tf.nn.softplus(read_strengths)
 
 # write_strengths: [batch_size, num_writes]
 write_strengths = Linear(
 output_size= self._num_writes,
 name='write_strengths')(interface_vector)
 write_strengths = 1 + tf.nn.softplus(write_strengths)
 
 
 # earse_vector: [batch_size, num_writes * word_size]
 erase_vectors = Linear(
 output_size= self._num_writes * self._word_size,
 name='erase_vectors')(interface_vector)
 erase_vectors = tf.reshape(
 erase_vectors, shape=[-1, self._num_writes, self._word_size])
 erase_vectors = tf.nn.sigmoid(erase_vectors)
 
 # write_vectors: [batch_size, num_writes * word_size]
 write_vectors = Linear(
 output_size= self._num_writes * self._word_size,
 name='write_vectors')(interface_vector)
 write_vectors = tf.reshape(
 write_vectors, shape=[-1, self._num_writes, self._word_size])
 
 
 # free_gates: [batch_size, num_reads]
 free_gates = Linear(
 output_size= self._num_reads,
 name='free_gates')(interface_vector)
 free_gates = tf.nn.sigmoid(free_gates)
 
 # allocation_gates: [batch_size, num_writes]
 allocation_gates = Linear(
 output_size= self._num_writes,
 name='allocation_gates')(interface_vector)
 allocation_gates = tf.nn.sigmoid(allocation_gates)
 
 # write_gates: [batch_size, num_writes]
 write_gates = Linear(
 output_size= self._num_writes,
 name='write_gates')(interface_vector)
 write_gates = tf.nn.sigmoid(write_gates)
 
 # read_modes: [batch_size, (1 + 2 * num_writes) * num_reads]
 num_read_modes = 1 + 2 * self._num_writes
 read_modes = Linear(
 output_size= self._num_reads * num_read_modes,
 name='read_modes')(interface_vector)
 read_modes = tf.reshape(
 read_modes, shape=[-1, self._num_reads, num_read_modes])
 read_modes = BatchApply(tf.nn.softmax)(read_modes)
 
 tape = {
 'read_content_keys': read_keys,
 'read_content_strengths': read_strengths,
 'write_content_keys': write_keys,
 'write_content_strengths': write_strengths,
 'write_vectors': write_vectors,
 'erase_vectors': erase_vectors,
 'free_gates': free_gates,
 'allocation_gates': allocation_gates,
 'write_gates': write_gates,
 'read_modes': read_modes,
 }
 return tape
 
 
 def _update_read_weightings(self,
 tape,
 memory,
 write_weightings,
 prev_read_weightings,
 prev_precedence_weightings,
 prev_link):
 """
 Calculates read weights for each read head.
 
 The read weights are a combination of following the link graphs in the
 forward or backward directions from the previous read position, and doing
 content-based lookup. The interpolation between these different modes is
 done by `inputs['read_mode']`.
 
 Args:
 inputs: Controls for this access module.
 This contains the content-based keys to lookup,
 and the weightings for the different read modes.
 
 memory: A tensor of shape `[batch_size, memory_size, word_size]`
 containing the current memory contents to do content-based lookup.
 
 prev_read_weights: A tensor of shape `[batch_size, num_reads, memory_size]`
 containing the previous read locations.
 
 link: A tensor of shape `[batch_size, num_writes, memory_size, memory_size]`
 containing the temporal write transition graphs.
 
 Returns:
 A tensor of shape `[batch_size, num_reads, memory_size]`
 containing the read weights for each read head.
 """
 with tf.name_scope(
 'update_read_weightings',
 values=[tape,
 memory,
 prev_read_weightings,
 prev_precedence_weightings,
 prev_link]):
 
 read_content_weightings = \
 self._read_content_mod(
 memory,
 tape['read_content_keys'],
 tape['read_content_strengths'])
 
 
 link,\
 precedence_weightings,\
 forward_weightings,\
 backward_weightings = \
 self._temporal_linkage(
 prev_link,
 prev_precedence_weightings,
 prev_read_weightings,
 write_weightings)
 
 
 backward_mode = tape['read_modes'][:, :, :self._num_writes]
 forward_mode = tape['read_modes'][:, :, self._num_writes:2 * self._num_writes]
 content_mode = tape['read_modes'][:, :, 2 * self._num_writes]
 
 backward_ = tf.expand_dims(backward_mode, axis=3) * backward_weightings
 backward_ = tf.reduce_sum(backward_, axis=2)
 
 forward_ = tf.expand_dims(forward_mode, axis=3) * forward_weightings
 forward_ = tf.reduce_sum(forward_, axis=2)
 
 content_ = tf.expand_dims(content_mode, axis=2) * read_content_weightings
 
 read_weightings = backward_ + forward_ + content_
 
 return read_weightings, link, precedence_weightings
 
 
 @property
 def state_size(self):
 """Returns a tuple of the shape of the state tensors."""
 memory = tf.TensorShape([self._memory_size, self._word_size])
 read_weightings = tf.TensorShape([self._num_reads, self._memory_size])
 write_weightings = tf.TensorShape([self._num_writes, self._memory_size])
 link = tf.TensorShape([self._num_writes, self._memory_size, self._memory_size])
 precedence_weightings = tf.TensorShape([self._num_writes, self._memory_size])
 usage = tf.TensorShape([self._memory_size])
 return (memory,
 read_weightings,
 write_weightings,
 precedence_weightings,
 link,
 usage)
 
 
 @property
 def output_size(self):
 """
 Returns the output shape.
 """
 return tf.TensorShape([self._num_reads, self._word_size])
 
 
 class DNCore_L1(RNNCore):
 """
 DNC core cell
 Args:
 controller: 控制器
 """
 
 def __init__(self,
 hidden_size= 128,
 memory_size= 256,
 word_size= 128,
 num_read_heads= 4,
 num_write_heads= 1,
 name='DNCore'):
 
 super().__init__(name=name) # 调用父类初始化
 with self._enter_variable_scope():
 self._controller = LSTM(hidden_size)
 self._access = MemoryAccess(
 memory_size= memory_size,
 word_size= word_size,
 num_reads= num_read_heads,
 num_writes= num_write_heads)
 
 self._dnc_output_size = \
 hidden_size + num_read_heads * word_size
 
 self._num_read_heads = num_read_heads
 self._word_size = word_size
 
 
 def _build(self, inputs, prev_tape):
 
 prev_controller_state,\
 prev_access_state,\
 prev_read_vectors = prev_tape
 
 batch_flatten = BatchFlatten()
 controller_input = tf.concat(
 [batch_flatten(inputs), batch_flatten(prev_read_vectors)], axis= 1)
 
 # 控制器处理数据
 controller_output, controller_state = \
 self._controller(controller_input, prev_controller_state)
 
 # 外存储器交互
 read_vectors, access_state = \
 self._access(controller_output, prev_access_state)
 
 # DNC 输出
 dnc_output = tf.concat(
 [controller_output, batch_flatten(read_vectors)], axis= 1)
 
 return dnc_output, (controller_state, access_state, read_vectors)
 
 
 def initial_state(self, batch_size, dtype=tf.float32):
 controller_state= self._controller.initial_state(batch_size, dtype)
 access_state= self._access.initial_state(batch_size, dtype)
 read_vectors= tf.zeros([batch_size, self._num_read_heads, self._word_size], dtype=dtype)
 return (controller_state, access_state, read_vectors)
 
 
 @property
 def state_size(self):
 controller_state= self._controller.state_size
 access_state= self._access.state_size
 read_vectors= tf.TensorShape([self._num_read_heads, self._word_size])
 return (controller_state, access_state, read_vectors)
 
 
 @property
 def output_size(self):
 return tf.TensorShape([self._dnc_output_size])
 
 
 class DNCore_L3(RNNCore):
 """
 DNC core cell
 Args:
 controller: 控制器
 """
 
 def __init__(self,
 hidden_size= 128,
 memory_size= 256,
 word_size= 128,
 num_read_heads= 3,
 num_write_heads= 1,
 name='DNCore'):
 
 super().__init__(name=name) # 调用父类初始化
 with self._enter_variable_scope():
 lstm_1 = LSTM(hidden_size)
 lstm_2 = LSTM(hidden_size)
 lstm_3 = LSTM(hidden_size)
 self._controller = DeepRNN([lstm_1, lstm_2, lstm_3])
 self._access = MemoryAccess(
 memory_size= memory_size,
 word_size= word_size,
 num_reads= num_read_heads,
 num_writes= num_write_heads)
 
 self._dnc_output_size = \
 hidden_size * 3 + num_read_heads * word_size
 self._num_read_heads = num_read_heads
 self._word_size = word_size
 
 
 def _build(self, inputs, prev_tape):
 
 prev_controller_state,\
 prev_access_state,\
 prev_read_vectors = prev_tape
 
 batch_flatten = BatchFlatten()
 controller_input = tf.concat(
 [batch_flatten(inputs), batch_flatten(prev_read_vectors)], axis= 1)
 
 # 控制器处理数据
 controller_output, controller_state = \
 self._controller(controller_input, prev_controller_state)
 
 # 外存储器交互
 read_vectors, access_state = \
 self._access(controller_output, prev_access_state)
 
 # DNC 输出
 dnc_output = tf.concat(
 [controller_output, batch_flatten(read_vectors)], axis= 1)
 return dnc_output, (controller_state, access_state, read_vectors)
 
 
 def initial_state(self, batch_size, dtype=tf.float32):
 controller_state= self._controller.initial_state(batch_size, dtype)
 access_state= self._access.initial_state(batch_size, dtype)
 read_vectors= tf.zeros([batch_size, self._num_read_heads, self._word_size], dtype=dtype)
 return (controller_state, access_state, read_vectors)
 
 
 @property
 def state_size(self):
 controller_state= self._controller.state_size
 access_state= self._access.state_size
 read_vectors= tf.TensorShape([self._num_read_heads, self._word_size])
 return (controller_state, access_state, read_vectors)
 
 
 @property
 def output_size(self):
 return tf.TensorShape([self._dnc_output_size])
 
 
 
 
 def _nested_add(nested_a, nested_b):
 """Add two arbitrarily nested `Tensors`."""
 return nest.map(lambda a, b: a + b, nested_a, nested_b)
 
 
 def _nested_unary_mul(nested_a, p):
 """Multiply `Tensors` in arbitrarily nested `Tensor` `nested_a` with `p`."""
 return nest.map(lambda a: p * a, nested_a)
 
 
 def _nested_zeros_like(nested_a):
 return nest.map(tf.zeros_like, nested_a)
 
 
 class ACTCore(rnn_core.RNNCore):
 """Adaptive computation time core.
 
 Implementation of the model described in "Adaptive Computation Time for
 Recurrent Neural Networks" paper, https://arxiv.org/abs/1603.08983.
 
 The `ACTCore` incorporates the pondering RNN of ACT, with different
 computation times for each element in the mini batch. Each pondering step is
 performed by the `core` passed to the constructor of `ACTCore`.
 
 The output of the `ACTCore` is made of `(act_out, (iteration, remainder)`,
 where
 
 * `iteration` counts the number of pondering step in each batch element;
 * `remainder` is the remainder as defined in the ACT paper;
 * `act_out` is the weighted average output of all pondering steps (see ACT
 paper for more info).
 """
 
 def __init__(self, core, output_size, threshold, get_state_for_halting,
 name="act_core"):
 """Constructor.
 
 Args:
 core: A `sonnet.RNNCore` object. This should only take a single `Tensor`
 in input, and output only a single flat `Tensor`.
 output_size: An integer. The size of each output in the sequence.
 threshold: A float between 0 and 1. Probability to reach for ACT to stop
 pondering.
 get_state_for_halting: A callable that can take the `core` state and
 return the input to the halting function.
 name: A string. The name of this module.
 
 Raises:
 ValueError: if `threshold` is not between 0 and 1.
 ValueError: if `core` has either nested outputs or outputs that are not
 one dimensional.
 """
 super(ACTCore, self).__init__(name=name)
 self._core = core
 self._output_size = output_size
 self._threshold = threshold
 self._get_state_for_halting = get_state_for_halting
 
 if not isinstance(self._core.output_size, tf.TensorShape):
 raise ValueError("Output of core should be single Tensor.")
 if self._core.output_size.ndims != 1:
 raise ValueError("Output of core should be 1D.")
 
 if not 0 <= self._threshold <= 1:
 raise ValueError("Threshold should be between 0 and 1, but found {}".
 format(self._threshold))
 
 def initial_state(self, *args, **kwargs):
 return self._core.initial_state(*args, **kwargs)
 
 @property
 def output_size(self):
 return tf.TensorShape([self._output_size]), (tf.TensorShape([1]),
 tf.TensorShape([1]))
 
 @property
 def state_size(self):
 return self._core.state_size
 
 @property
 def batch_size(self):
 self._ensure_is_connected()
 return self._batch_size
 
 @property
 def dtype(self):
 self._ensure_is_connected()
 return self._dtype
 
 def _cond(self, unused_x, unused_cumul_out, unused_prev_state,
 unused_cumul_state, cumul_halting, unused_iteration,
 unused_remainder):
 """The `cond` of the `tf.while_loop`."""
 return tf.reduce_any(cumul_halting < 1)
 
 def _body(self, x, cumul_out, prev_state, cumul_state,
 cumul_halting, iteration, remainder, halting_linear, x_ones):
 """The `body` of `tf.while_loop`."""
 # Increase iteration count only for those elements that are still running.
 all_ones = tf.constant(1, shape=(self._batch_size, 1), dtype=self._dtype)
 is_iteration_over = tf.equal(cumul_halting, all_ones)
 next_iteration = tf.where(is_iteration_over, iteration, iteration + 1)
 out, next_state = self._core(x, prev_state)
 # Get part of state used to compute halting values.
 halting_input = halting_linear(self._get_state_for_halting(next_state))
 halting = tf.sigmoid(halting_input, name="halting")
 next_cumul_halting_raw = cumul_halting + halting
 over_threshold = next_cumul_halting_raw > self._threshold
 next_cumul_halting = tf.where(over_threshold, all_ones,
 next_cumul_halting_raw)
 next_remainder = tf.where(over_threshold, remainder,
 1 - next_cumul_halting_raw)
 p = next_cumul_halting - cumul_halting
 
 next_cumul_state = _nested_add(cumul_state,
 _nested_unary_mul(next_state, p))
 
 next_cumul_out = cumul_out + p * out
 
 return (x_ones, next_cumul_out, next_state, next_cumul_state,
 next_cumul_halting, next_iteration, next_remainder)
 
 def _build(self, x, prev_state):
 """Connects the core to the graph.
 
 Args:
 x: Input `Tensor` of shape `(batch_size, input_size)`.
 prev_state: Previous state. This could be a `Tensor`, or a tuple of
 `Tensor`s.
 
 Returns:
 The tuple `(output, state)` for this core.
 
 Raises:
 ValueError: if the `Tensor` `x` does not have rank 2.
 """
 x.get_shape().with_rank(2)
 self._batch_size = x.get_shape().as_list()[0]
 self._dtype = x.dtype
 
 x_zeros = tf.concat(
 [x, tf.zeros(
 shape=(self._batch_size, 1), dtype=self._dtype)], 1)
 x_ones = tf.concat(
 [x, tf.ones(
 shape=(self._batch_size, 1), dtype=self._dtype)], 1)
 # Weights for the halting signal
 halting_linear = basic.Linear(name="halting_linear", output_size=1)
 
 body = functools.partial(
 self._body, halting_linear=halting_linear, x_ones=x_ones)
 cumul_halting_init = tf.zeros(shape=(self._batch_size, 1),
 dtype=self._dtype)
 iteration_init = tf.zeros(shape=(self._batch_size, 1), dtype=self._dtype)
 core_output_size = [x.value for x in self._core.output_size]
 out_init = tf.zeros(shape=(self._batch_size,) + tuple(core_output_size),
 dtype=self._dtype)
 cumul_state_init = _nested_zeros_like(prev_state)
 remainder_init = tf.zeros(shape=(self._batch_size, 1), dtype=self._dtype)
 (unused_final_x, final_out, unused_final_state, final_cumul_state,
 unused_final_halting, final_iteration, final_remainder) = tf.while_loop(
 self._cond, body, [x_zeros, out_init, prev_state, cumul_state_init,
 cumul_halting_init, iteration_init, remainder_init])
 
 act_output = basic.Linear(
 name="act_output_linear", output_size=self._output_size)(final_out)
 
 # 修改,控制器state和读向量使用 pondering 累加权重系数方式,
 # 记忆矩阵不使用,记忆矩阵保持展开时间连续性
 controller_state, access_state, read_vectors = final_cumul_state
 final_cumul_state = (controller_state, unused_final_state[1], read_vectors)
 
 return (act_output, (final_iteration, final_remainder)), final_cumul_state
 
 
 
 |